home *** CD-ROM | disk | FTP | other *** search
/ No Fragments Archive 12: Textmags & Docs / nf_archive_12.iso / MAGS / SOURCES / ATARI_SRC.ZIP / atari source / AHDI / SYQUEST / SQHDX / AHDI.S < prev    next >
Encoding:
Text File  |  2001-02-09  |  90.9 KB  |  3,056 lines

  1. ; Apr 11 1989 v3.00'
  2.  
  3. ;------------------------------------------------------------------------
  4. ;                                    :
  5. ;    AHDI Hard Disk Driver for the Atari ST                :
  6. ;    Copyright 1985,1986,1987,1988,1989 Atari Corp.            :
  7. ;    All Rights Reserved                        :
  8. ;                                    :
  9. ;------------------------------------------------------------------------
  10.  
  11.  
  12. ;----------------
  13. ;
  14. ;  Conditional Assembly Switches
  15. ;
  16. format        equ    0        ; Format code
  17. mdsense        equ    0        ; Mode Sense code
  18. ospool        equ    1        ; increase size of OS pool for ROM
  19.  
  20.  
  21. ;
  22. ;-------------------- Edit History ------------------------
  23.  
  24. ;------------------
  25. ;                                    :
  26. ;  9-Apr-1985 lmd    Hacked it up.  "Gee, it seems to work ..."    :
  27. ; 14-Apr-1985 lmd    linked with BIOS (***FOR NOW***)        :
  28. ; 20-Apr-1985 lmd    hacked for WD controller (now, wired...)    :
  29. ; 24-Jun-1985 jwt    hacked for Adaptec, new kludge board        :
  30. ; 01-Jul-1985 jwt    seems to work, add more formatting and more    :
  31. ;             detailed error reporting            :
  32. ; 22-Jul-1985 jwt    change timing of wdc/wdl at start of command,    :
  33. ;             added extra move.w $8a,wdl to change A1    :
  34. ; 23-Jul-1985 jwt    use a move.l instruction for all wdc/wdl write    :
  35. ;             pairs since it changes A1 quickly enough that    :
  36. ;             the (old) DMA chip does not incorrectly    :
  37. ;             generate two chip selects            :
  38. ; 26-Sep-1985 jwt v0.05    support multiple ACSI devices            :
  39. ;            separate timeouts for command packet and    :
  40. ;             operation                    :
  41. ; 01-Oct-1985 jwt v0.06    added some AUXout serial debug messages        :
  42. ;            was responding to one more drive than was there    :
  43. ; 07-Oct-1985 jwt v0.07    added support for multiple partitions/drive    :
  44. ; 11-Oct-1985 jwt v0.08 added delay loop after pread for completion    :
  45. ;             byte                        :
  46. ; 19-Oct-1985 jwt v0.09    remove format and simple commands from resident :
  47. ;             part                        :
  48. ;            conditional assembly for default size        :
  49. ;            added count parameter to pread            :
  50. ; 22-Oct-1985 jwt v0.10    make certain qdone returns d0=-1 on timeout    :
  51. ;            add bits to read/write flag for:        :
  52. ;             retry disable (bit 2)                :
  53. ;             physical unit operation (bit 3)        :
  54. ;            add pun_ptr to TOS global variables        :
  55. ; 24-Oct-1985 jwt v0.11    add critical error call on errors        :
  56. ; 30-Jan-1986 lmd v0.12    increase OS pool by 128 chunks for ROM release    :
  57. ;             of 11/20/85                    :
  58. ;          jwt    stay resident if any physical units found    :
  59. ;             rather than if any GEM partitions found    :
  60. ; 05-Feb-1986 jwt    call critical error handler on errors unless    :
  61. ;             no-retry bit is set                :
  62. ;            conditional assembly format code        :
  63. ;            remove transfer only to even byte boundary    :
  64. ;             restriction                    :
  65. ;            remove transfer less than 128K restriction    :
  66. ;            check for 0 length transfer            :
  67. ; 06-Feb-1986 jwt v0.13    use register based accesses for wdc and wdl    :
  68. ; 25-Mar-1986 lmd v0.14 Enforce .005 (200th) sec delay between        :
  69. ;             successive calls to _do_rw().  SCSI adapter    :
  70. ;             board eats the controller's completion byte,    :
  71. ;             so we have to delay for it.            :
  72. ; 24-Apr-1986 lmd v1.1    Hack pool_install code to increase pool for    :
  73. ;             other ROM releases of the system.        :
  74. ; 24-Apr-1986 lmd v1.4    Print nasty messages for old disk-based and    :
  75. ;             unauthorized ROM-based systems.        :
  76. ; 23-Jun-1987 lmd v1.5  Fix date-check in nasty-OS-message code; wrong    :
  77. ;             offset into the OS header (now $1e).        :
  78. ; 06-Nov-1987 akp v1.7    Added procedure findpackages and call to it.    :
  79. ; 10-Nov-1987 akp    Changed source to MADMAC format.        :
  80. ;            Removed format flag from top of file.        :
  81. ; 24-Nov-1987 akp    Really made v1.7 work.                :
  82. ; 19-Feb-1988 ml    Added format and mode sense code for use in     :
  83. ;             HDX  (It's conditional, code will only be    :
  84. ;             included for ahdi.prg, and not shdriver.sys).    :
  85. ; 26-May-1988 ml    Added request sense code for use in HDX 3.0    :
  86. ;             for SR444 (Syquest drive).            :
  87. ; ??-Aug-1988 ml  v2.0    Attempted to add code for removable media.    :
  88. ; 07-Sep-1988 ml    Found out that shouldn't move code around too    :
  89. ;             much.  Labels i_sasi and i_sasi1 are used to    :
  90. ;             determine which part of this program will be    :
  91. ;             reserved at Ptermres().  All text and data to    :
  92. ;             be reserved should appear between these two    :
  93. ;             labels.                    :
  94. ; 31-Oct-1988 ml    It seemed to work well.  Now AHDI can handle    :
  95. ;             both removable and non-removable hard disks.    :
  96. ;            It can handle hard disks partitioned in    GEMDOS    :
  97. ;             format or MSDOS 3.x format.              :
  98. ;            Code for executing programs in the AUTO folder     :
  99. ;             and packages in RAM, and code for bringing up    :
  100. ;             AES have been deleted.  Instead, AHDI returns    :
  101. ;             to TOS ROMs and let them handle those tasks.    :
  102. ; 01-Dec-1988 ml    Modified _sasi_rw so that it will look for a     :
  103. ;             LONG record number after the device number, if :
  104. ;             the WORD record number == -1.  This allows the    :
  105. ;             caller of Rwabs to address pass 32Mb.        :
  106. ;             Though the underlying routine is the same, the    :
  107. ;             caller has to call Lrwabs from the high level,    :
  108. ;             not Rwabs for this to work.            :
  109. ; 02-Dec-1988 ml    Modified the way we check whether we should jam    :
  110. ;             d7 for further boot before returning to TOS    :
  111. ;             ROMs.  The system build date is being checked    :
  112. ;             instead of the OS version number.  This is    :
  113. ;             necessary because there seems to be confusion    :
  114. ;             about version numbers of some released ROMS.    :
  115. ; 05-Dec-1988 ml    If OS wasn't built before 4/22/1987, when     :
  116. ;             returning to TOS ROMs, jam d7 with the last     :
  117. ;             unit that was processed, instead of magic #.    :
  118. ; 08-Dec-1988 ml    If ospool code is included, make sure 'poolbuf'    :
  119. ;             is the last label in the program to be kept.    :
  120. ;             The code uses the memory after that label as    :
  121. ;             a buffer.  Whatever is after 'poolbuf' will be :
  122. ;             overwritten.                    :
  123. ; 04-Jan-1989 ml    Modified to handle more than 4 partitions per    :
  124. ;             physical unit.  The method used is the same as    :
  125. ;             used in MSDOS 3.3 (ie., by implementing a     :
  126. ;             linked list of logical drives).  There is a     :
  127. ;             type of partition called the EXTENDED GEMDOS    :
  128. ;             PARTITION which is head of the linked list.    :
  129. ;             This new type of partition is specified by the    :
  130. ;             value "XGM" in the p_id field of the partition    :
  131. ;             map.                        :
  132. ; 22-Feb-1989 ml v2.07a    Modified _fdone() and _qdone() to use 200 hz    :
  133. ;             clock for timeout loop.  This would keep the    :
  134. ;             timeout constant over different machines.    :
  135. ; 02-Mar-1989 ml v2.08a Moved pbuf up with regular declarations.  It    :
  136. ;             should stay resident.  Added a cookie pointer    :
  137. ;             for people to check if they have gotten this    :
  138. ;             new version of ahdi.                :
  139. ; 03-Mar-1989 ml    Changed cookie to 'AHDI'.  It will stay that     :
  140. ;             way.  Added version #, a long, right after    :
  141. ;             cookie ptr.                      :
  142. ;             Example: 19890208                :
  143. ;                 1989 - year 1989;            :
  144. ;                 02 - major version #;            :
  145. ;                 08 - minor version #;            :
  146. ; 06-Mar-1989 ml     Enforced 0.005 sec delay between driver calls.    :
  147. ;             Delay only when neccessary before 1st command    :
  148. ;             byte is sent, and update timer when command is    :
  149. ;             done.  New routine _delay().  Update timer     :
  150. ;             code is added in _endcmd().            :
  151. ; 07-Mar-1989 ml    More optimization done on low-level driver.    :
  152. ;             Use registers instead of wdlwdc when accessing    :
  153. ;             DMA registers, etc...                :
  154. ; 09-Mar-1989 ml    Forced driver to stay around even when no drive    :
  155. ;             is found.                    :
  156. ;            Made number of drive to reserve for each ACSI     :
  157. ;             Syquest drive patchable.            :
  158. ;             Magic number $f0ad is used to denote a version    :
  159. ;             with patchable variables.            :
  160. ;             Version number (same as one after the cookie    :
  161. ;             pointer) is stored after magic # $f0ad.    :
  162. ; 10-Mar-1989 ml    Made number of memory chunks to add to ospool    :
  163. ;             patchable.                    :
  164. ; 13-Mar-1989 ml v2.09a    If there is no cartridge in a Syquest drive,    :
  165. ;             return drive not ready, and pass to critical    :
  166. ;             error handler.                    :
  167. ; 29-Mar-1989 ml v2.10a Verion number is now a word, MMmm.        :
  168. ;             (MM - major #; mm - minor #)            :
  169. ;            Added in checks to see if enough memory is    :
  170. ;             allocated for ospool installation and big    :
  171. ;             GEMDOS buffer lists.                :
  172. ; 30-Mar-1989 ml    If there is not enough memory for big GEMDOS    :
  173. ;             buffer lists, make maximum sector size = 512.    :
  174. ;             This guarantees that the regular partitions     :
  175. ;             are still accessible.                :
  176. ;            If there is not enough memory to install amount    :
  177. ;             of OS pool requested. NONE would be installed. :
  178. ;            Variable 'poolbuf' is gone.            :
  179. ; 04-Apr-1989 ml    Sped up media change.  Refer to comments at    :
  180. ;            _sasi_mediach.                    :
  181. ; 11-Apr-1989 ml v3.00    Made version # consistent with HDX and HINSTALL.:
  182. ;------------------------------------------------------------------------
  183.  
  184.  
  185. ;
  186. ;------------  Equates and Declarations--------------
  187.  
  188. etv_critic    equ    $404        ; critical error handoff vector
  189. phystop        equ    $42e        ; physical top of memory
  190. flock        equ    $43e        ; FIFO lock variable
  191. _bootdev    equ    $446        ; default boot device
  192. hdv_init    equ    $46a        ; hdv_init()    ** UNUSED **
  193. hdv_bpb        equ    $472        ; hdv_bpb(dev)
  194. hdv_rw        equ    $476        ; hdv_rw(rw, buf, count, recno, dev)
  195. hdv_boot    equ    $47a        ; hdv_boot()    ** UNUSED **
  196. hdv_mediach    equ    $47e        ; hdv_mediach(dev)
  197. _bufl        equ    $4b2        ; 2 buffer-list headers
  198. _hz_200        equ    $4ba        ; system 200hz timer
  199. _drvbits    equ    $4c2        ; block device bitVector
  200. _dskbufp    equ    $4c6        ; pointer to common disk buffer
  201. _sysbase    equ    $4f2        ; -> base of OS
  202. pun_ptr        equ    $516        ; number of physical units
  203.  
  204. ;+
  205. ; Restraints 
  206. ;-
  207. MAXUNITS    equ    14        ; max # of log units w/o drv A & B
  208. MAXACSI        equ    8        ; maximum number of ACSI devices
  209. MAXSECTORS    equ    254        ; maximum no. of sectors at one gulp
  210.  
  211. ;+
  212. ; Offsets to ...
  213. ;-
  214. DOSPM        equ    $1be        ; MSDOS boot sect's partition map
  215. DOSSIG        equ    $1fe        ; MSDOS boot sect's signature
  216. HDSIZ        equ    $1c2        ; offset to GEMDOS root sect's 
  217.                     ; hard disk size
  218.  
  219. ;+
  220. ; Constants and Variables
  221. ;-
  222. SIG        equ    $55aa        ; signature for valid MSDOS boot sects
  223. NRETRIES    equ    3        ; #retries-1
  224. MAXNPART    equ    3        ; #partition entries in root sect - 1
  225. BPBLEN        equ    18        ; length of bpb entry in bytes
  226. FATLEN        equ    64        ; max fat size = 64 sectors
  227.                     ; (for 16Mb drive, 2 spc, 512 bps)
  228. SERLEN        equ    3        ; length of a serial # in bytes
  229. CHKDATE        equ    $19870422    ; ROM date for bootstop checking
  230.  
  231. ;+
  232. ; BIOS error codes
  233. ;-
  234. EDRVNR        equ    -2        ; driver not ready
  235. EWRITF        equ    -10        ; write fault
  236. EREADF        equ    -11        ; read fault
  237. EWRPRO        equ    -13        ; write on write-protected media
  238. E_CHNG        equ    -14        ; media change detected
  239. CRITRETRY    equ    $00010000    ; "retry" return code
  240.  
  241. ;+
  242. ; SCSI error codes
  243. ;-
  244. DRVNRDY        equ    $4        ; drive not ready
  245. WRTPRTD        equ    $27        ; write on write-protected media
  246. MDMCHGD        equ    $28        ; media change detected
  247.  
  248. ;+
  249. ; Number of bytes per Buffer Control Block (excluding the data block itself)
  250. ;
  251. ; struct_bcb {
  252. ;     struct_bcb    *b_link;    /* 4 bytes */
  253. ;    int        b_neg1;        /* 2 bytes */
  254. ;    int        b_private[5];    /* 10 bytes */
  255. ;    char        *b_bufr;    /* 4 bytes */
  256. ; };
  257. ;
  258. ; For GEMDOS buffer lists.
  259. ;-
  260. BCBLEN        equ    20
  261.  
  262. ;+
  263. ; for extension of os pool
  264. ;-
  265. chunksiz    equ     66        ; #bytes/chunk
  266. chunkno        equ     4        ; chunk# (4 16-byte chunks)
  267.  
  268.  
  269. ;
  270. ;----------------
  271. ;
  272. ;  Entry points:
  273. ;
  274. ;    +0   GEMDOS entry point (double-click, or \AUTO folder on floppy)
  275. ;    +4   Boot entry point (from driver file off of C:)
  276. ;    +8   Reserved for future use
  277. ;    +$C  $F0AD magic number
  278. ;    +$E  version number
  279. ;    +$12 # chunks of ospool to add
  280. ;    +$14 # of sqnpart entries that follows
  281. ;    +$16 first sqnpart entry
  282. ;
  283. ;  if bootloaded, d0 = # bytes allocated by boot code.
  284. ;
  285. i_sasi:    bra    gboot            ; GEMDOS entry-point
  286.     bra    iboot            ; Boot entry-point
  287.     bra    iboot            ; (unused, reserved)
  288.  
  289.  
  290. ;----------------
  291. ;
  292. ;  Patchable variables
  293. ;
  294. magicnum:    dc.w    $f0ad        ; wasn't here in previous releases
  295. vernum:        dc.w    $0300        ; version number
  296. numchunks:    dc.w    128        ; # chunks of ospool to add
  297. minbigsect:    dc.w    512        ; minimum size of a big sector
  298. numsqnpart:    dc.w    MAXACSI        ; number of sqnpart entries to follow
  299. minsqnpart:    dcb.b    MAXACSI,1    ; minimum # drives for removable unit
  300. .even
  301.  
  302. ;----------------
  303. ;
  304. ;  GEMDOS entry;
  305. ;    find amount of memory availble and store in d0.l
  306. ;
  307. gboot:    movea.l    4(sp),a2        ; a2 -> basepage
  308.     move.l    4(a2),d0        ; d0 = available memory
  309.     sub.l    (a2),d0            ;    = p_hitpa - p_lowtpa - basepage
  310.     sub.l    #$0100,d0
  311.     bra    i_sasi1            ; (continue with normal initialization)
  312.  
  313.  
  314. ;----------------
  315. ;
  316. ;  Boot entry;
  317. ;    set "bootloaded", record base address from boot loader, 
  318. ;    and continue with normal boot process.
  319. ;
  320. iboot:    st    bootloaded        ; boot entry-point, set flag
  321.     sub.l    #$1c,d0            ; memory available -= file header
  322.     move.l    a2,baseaddr        ; install base address
  323.                     ; a2 = beginning addr of this block
  324.     bra    i_sasi1            ; (continue with normal initialization)
  325.  
  326.  
  327. ;
  328. ;--------------- Driver State --------------------
  329.  
  330.         dc.b    13,'AHDI : Apr 11 1989 v3.00'
  331.         dc.b    13,10,$bd,'Atari Corp. 1985, 1986, 1987, 1988, 1989'
  332.         dc.b    13,10,0,$1A
  333. .even
  334.  
  335. _puns:
  336. puns:        dc.w    0        ; # of physical units on user's system
  337.  
  338. dummy1:        dcb.b    2,-1        ; dummy pun entries for A and B
  339. _pun:
  340. pun:        dcb.b    MAXUNITS,0    ; physical unit table
  341. .even
  342.  
  343. dummy2:        dcb.l    2,0        ; dummy start entries for A and B
  344. _partstart:
  345. start:        dcb.l    MAXUNITS,0    ; partition start table
  346.  
  347. _cookie:                ; *** DON'T CHANGE ***
  348. cookie:        dc.l    $41484449    ; cookie = 'AHDI'
  349.  
  350. _cookptr:
  351. cookptr:    dc.l    0        ; pointer to cookie
  352.  
  353. _versn:
  354. versn:        dc.w    $0300        ; version number: MMmm
  355.  
  356. _maxssz:
  357. maxssz:        dc.w    512        ; maximum sector size allowed
  358.         dcb.l    16,0        ; reserved for future use
  359.  
  360. bpbs:    dcb.b    BPBLEN,0        ; a bpb 
  361. mcflgs:    dcb.b    MAXUNITS,2        ; media change flag table
  362. xst:    dcb.b    MAXUNITS,1        ; drive existence flag table
  363. serno:    dcb.b    MAXUNITS*SERLEN,0    ; serial number table
  364. sratio:    dcb.b    MAXUNITS,1        ; log sect size : phys sect size tbl
  365. fatsum:    dcb.b    MAXUNITS*FATLEN,0    ; FAT checksum table
  366. fatst:    dcb.w    MAXUNITS,0        ; starting sector # of last FAT
  367. fatend:    dcb.w    MAXUNITS,0        ; ending sector # of last FAT
  368.  
  369. bootloaded:    dc.w    0        ; nonzero if loaded from boot sector
  370. memalloc:    dc.l    0        ; total memory available if bootloaded
  371. baseaddr:    dc.l    0        ; -> base addr of .PRG file
  372. tokeep:        dc.l    0        ; amount memory to keep
  373. preadret:    dc.w    0        ; return code from pread
  374.  
  375. cpun:        dc.w    0        ; current physical unit
  376. npart:        dc.w    0        ; number of partitions found
  377. bfat:        dc.w    0        ; 0: 12-bit FAT; 1: 16-bit FAT
  378.  
  379. strec:        dc.l    0        ; starting sector to read/write
  380. endrec:        dc.l    0        ; last sector to read/write
  381. stbuf:        dc.l    0        ; starting address of buffer
  382. rmbits:        dc.b    0        ; bit map - 1: unit is removable
  383. scsi:        dc.b    0        ; bit map - 1: embedded SCSI drive
  384.  
  385. _retries:    dc.w    NRETRIES    ; number of retries to do
  386. retrycnt:    dc.w    1        ; retry counter
  387.  
  388. o_bpb:        dc.l    1
  389. o_rw:        dc.l    1
  390. o_mediach:    dc.l    1
  391.  
  392. sendata:    dcb.b    16,0        ; buffer for request sense
  393.  
  394. lastacstm:    dc.l    0        ; controller last accessed time
  395. lastmdctm:    dc.l    0        ; time media change was last called
  396. pbuf:        dc.l    0        ; ptr to start of root sector image
  397. fsiz:        dc.w    0        ; FAT size in sectors
  398. fatrec:        dc.w    0        ; 2nd FAT starting sector
  399. sizr:        dc.w    1        ; ratio of log : phys sector size
  400. temp:        dc.l    0        ; temporary storage
  401. savssp:        dc.l    1        ; (saved SSP)
  402. mcrw:        dc.b    0        ; if TRUE, r/w returns media change
  403. ext:        dc.b    0        ; if =0, not processing ext partition
  404.  
  405. extrt:        dc.l    0        ; starting sector of ext DOS partition
  406. extvol:        dc.l    0        ; offset wrt ext DOS partition
  407. pbpb:        dc.w    0        ; partition # for dev
  408. .even
  409.  
  410.  
  411. ;
  412. ;------------------ Front End ------------------
  413.  
  414. ;----------------
  415. ;
  416. ;  Return pointer to BPB (or NULL)
  417. ;
  418. ;    Synopsis:    LONG hbpb(dev)
  419. ;        WORD dev;    4(sp).w
  420. ;
  421. hbpb:    move.w    4(sp),d0        ; d0 = devno
  422.     clr    d1            ; d1 = 0, physical op not possible
  423.     movea.l    o_bpb,a0        ; a0 -> pass-through vector
  424.     lea    _sasi_bpb(pc),a1    ; a1 -> our handler
  425.     bra.s    check_dev        ; do it
  426.  
  427.  
  428. ;----------------
  429. ;
  430. ;  Read or write logical sectors
  431. ;
  432. ;    Synopsis:    LONG rw(rw, buf, count, recno, dev)
  433. ;        WORD rw;    $4(sp).w
  434. ;        char *buf;    $6(sp).l
  435. ;        WORD count;    $a(sp).w
  436. ;        WORD recno;    $c(sp).w
  437. ;        WORD dev;    $e(sp).w
  438. ;
  439. hrw:    move.w    $e(sp),d0        ; d0 = devno
  440.     move.w    4(sp),d1        ; d1 includes physical device flag
  441.     movea.l    o_rw,a0            ; a0 -> pass-through vector
  442.     lea    _sasi_rw(pc),a1        ; a1 -> our handler
  443.     bra.s    check_dev        ; do it
  444.  
  445.  
  446. ;----------------
  447. ;
  448. ;  Check for media change
  449. ;
  450. ;    Synopsis:    LONG mediach(dev)
  451. ;        WORD dev;    4(sp).W
  452. ;
  453. hmediach:
  454.     move.w    4(sp),d0        ; d0 = devno
  455.     clr    d1            ; physical operation not possible
  456.     movea.l    o_mediach,a0        ; a0 -> pass-through vector
  457.     lea    _sasi_mediach(pc),a1    ; a1 -> our handler
  458.  
  459.  
  460. ;----------------
  461. ;
  462. ;  check_dev - use handler, or pass vector through
  463. ;
  464. ;  Passed:    d0.w = device#
  465. ;        d1, bit 3  1=physical operation
  466. ;        a0 ->  old handler
  467. ;        a1 ->  new handler
  468. ;        a5 ->  $0000 (zero-page ptr)
  469. ;
  470. ;  Jumps-to:    (a1) if dev in range for this handler
  471. ;        (a0) otherwise
  472. ;
  473. check_dev:
  474.     subq    #2,d0            ; lowest device is 2 (unit 0 or C:)
  475.     bmi.s    chkd_f            ; if lower, not one of ours
  476.  
  477.     btst    #3,d1            ; is this a physical unit operation?
  478.     beq.s    chkd_a            ; if not set, go to chkd_a
  479.  
  480.     cmp    puns,d0            ; compare unit num to num units exist
  481.     bge.s    chkd_f            ; if unit num too big, not one of ours
  482.     bra.s    chkd_s            ; else it IS one of of ours
  483.  
  484. chkd_a:    lea    pun,a2            ; pointer to pun map
  485.     tst.b    0(a2,d0.w)        ; must be positive for a real unit
  486.     bmi.s    chkd_f
  487. chkd_s:    movea.l    a1,a0            ; yes -- follow success vector
  488. chkd_f:    jmp    (a0)            ; do it
  489.  
  490.  
  491. ;
  492. ;------------------ Medium-Level Driver ----------------
  493.  
  494. ;----------------
  495. ;
  496. ;  Return BPB for logical device
  497. ;
  498. ;    Synopsis:    LONG _sasi_bpb(dev)
  499. ;        WORD dev;    $4(sp).w
  500. ;
  501. ;    Returns:    NULL, or a pointer to the BPB buffer
  502. ;
  503. ; 10-21-88    ml.    I am not making a special case for non-removable
  504. ;            hard disk, because if a program uses Allan's
  505. ;            program to force a media change, the program 
  506. ;            should be getting the "Real" AND "New" BPB.
  507. ;            (The old (v1.7 and before) AHDI only index into
  508. ;            the bpbs table and return the pointer, without
  509. ;            actually go and read the boot sector of the dev.)
  510. ;
  511. _sasi_bpb:
  512.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  513. bpbst:    move.w    4(sp),d1        ; d1 = device number
  514.     lea    pun,a0            ; a0 = ptr to pun table
  515.     adda.w    d1,a0            ; a0 = ptr to pun @ dev's entry
  516.     clr.w    d2            ; coerce byte to word
  517.     move.b    (a0),d2            ; d2.w = pun that dev belongs to
  518.  
  519.     lea    xst,a1            ; a0 = ptr to drive existence table
  520.     tst.b    (a1,d1.w)        ; does drive exist?
  521.     bne.s    bpbgo            ; if it does, go on normally
  522.                     ; else, see if it really doesn't exist
  523.     movem.w    d1-d2,-(sp)        ; else save registers
  524.     move.w    d2,-(sp)        ; physical unit number
  525.     bsr    testunit        ; verify by doing test unit ready
  526.     addq.l    #2,sp            ; cleanup stack
  527.     movem.w    (sp)+,d1-d2        ; restore registers
  528.     tst.w    d0            ; return good status?
  529.     beq    badbpb            ; if yes, ie. medium has not changed
  530.                     ; therefore, dev still doesn't exist
  531.     moveq    #1,d0            ; else medium may have changed
  532.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  533.     bra.s    bpbst            ; restart procedure
  534.  
  535. bpbgo:    move.w    d2,cpun            ; cpun = pun(dev)
  536.     move.l    _dskbufp,pbuf        ; pbuf = ptr to 2nd half of 1K disk buf
  537.     add.l    #512,pbuf
  538.  
  539. bpb00:    move.l    a0,-(sp)        ; save ptr to pun(dev)
  540.     move.w    #1,-(sp)        ; return media change if detected
  541.     move.w    cpun,-(sp)        ; physical unit number
  542.     move.l    pbuf,-(sp)        ; buffer to read into
  543.     move.w    #1,-(sp)        ; read in 1 sector
  544.     clr.l    -(sp)            ; from sector 0
  545.     bsr    pread            ; pread(sectno, cnt, buf, phys#, flag)
  546.     adda    #14,sp
  547.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  548.     tst    d0            ; pread successful?
  549.     beq.s    bpb0            ; if yes, go on normally
  550.  
  551. bpberr:    cmpi.w    #E_CHNG,d0        ; is media change detected?
  552.     beq.s    bpbchg            ; if so, set mcflgs
  553.                     ; else call up error handler
  554.     move.l    a0,-(sp)        ; save ptr to pun(dev)
  555.     move.w    8(sp),d1        ; a0 = drive # excluding A: and B:
  556.     bsr    critic            ; call up critical error handler
  557.     move.l    (sp)+,a0        ; restore ptr to pun(dev)
  558.     cmpi.l    #CRITRETRY,d0        ; retry?
  559.     beq.s    bpb00            ; if so, go and try again
  560.     bra    badbpb            ; else return no BPB
  561.  
  562. bpbchg:    move.b    #1,d0            ; d0.b = media may be changed
  563.     move.w    4(sp),d1        ; d1.w = device number
  564.     move.b    cpun+1,d2        ; d2.b = physical unit number
  565.     bsr    s_mc_xst        ; go set mcflgs and xst flags
  566.     bra    bpbst            ; restart procedure
  567.  
  568. bpb0:    move.w    cpun,d2            ; d2 = physical unit number of dev
  569.     move.w    #0,pbpb            ; pbpb = partition # dev corresponds
  570. bpb1:    cmp.b    -(a0),d2        ; pun that dev belongs to == (a0)?
  571.     bne.s    bpb2
  572.     addq.w    #1,pbpb
  573.     bra.s    bpb1
  574.  
  575. bpb2:    move.w    #MAXNPART,d1        ; do #MAXNPART times
  576.     movea.l    pbuf,a0            ; a0 = ptr to beginning of root sector
  577.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  578.     bne.s    bpb3            ; if not, assume it's in GEMDOS format
  579.     bsr    dosbpb            ; else, handle it the DOS way
  580.     bra.s    bpb4            ; else, go get the bpb
  581. bpb3:    move.w    #1,bfat            ; 16 bit FAT always for GEMDOS
  582.     bsr    gembpb            ; handle it the GEMDOS way
  583. bpb4:    tst.w    d0            ; successful?
  584.     beq.s    bpbnf            ; if =0, no valid BPB found
  585.     bpl.s    bpb5            ; if +ive, valid BPB found
  586.     cmpi.w    #E_CHNG,d0        ; else media changed?
  587.     beq.s    bpbchg            ; if so, restart procedure
  588.     bra.s    badbpb            ; else no BPB found
  589.                     ; partition not found
  590. bpbnf:    lea    xst,a0            ; a0 = ptr to drive existence table
  591.     move.w    4(sp),d0        ; d0 = dev number
  592.     clr.b    (a0,d0.w)        ; dev definitely does not exist
  593.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  594.     move.b    #2,(a0,d0.w)        ; set as medium has changed
  595.     bra.s    badbpb            ; can't find such a partition
  596.  
  597. bpb5:    move.l    d1,-(sp)        ; start_sector
  598.     move.w    8(sp),-(sp)        ; dev number
  599.     bsr    getbpb            ; getbpb(dev, start_sector)
  600.     addq.l    #6,sp            ; clean up stack
  601.     tst.l    d0            ; getbpb successful?
  602.     bpl.s    retbpb            ; if so, return ptr to bpb
  603.     cmpi.w    #E_CHNG,d0        ; media changed?
  604.     beq    bpbchg            ; if so, restart procedure
  605. badbpb:    moveq    #0,d0            ; return no bpb found
  606. retbpb:    rts
  607.  
  608.  
  609. ;
  610. ;+
  611. ; dosbpb - find the DOS partition that corresponds to the requested
  612. ;       logical drive
  613. ; Passed:
  614. ;    a0 = buffer address for root sector
  615. ;    d1 = number of entries in partition map
  616. ;
  617. ; Assumed:
  618. ;    pbpbs = partition being looked for
  619. ;
  620. ; Returns:
  621. ;    d0.b = 0        if partition not found
  622. ;         = negative #    some kind of error
  623. ;         = positive #    system indicator of the partition
  624. ;    d1.l = starting sector of the partition (if it is found)
  625. ;-
  626. dosbpb:    adda.w    #DOSPM,a0        ; a0 = ptr to partition map
  627. dbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  628.     sf    ext            ; not dealing with ext partition
  629.     bsr    fdpart            ; find a partition
  630.     tst.b    d0            ; found any?
  631.     beq.s    dbpba            ; not a valid partition
  632.     cmpi.b    #5,d0            ; extended partition?
  633.     bne.s    dbpb1            ; if not, it's a regular partition
  634.     st    ext            ; else, it's an extended partition
  635.     move.l    #0,extvol        ; offset from start of partition = 0
  636.     move.l    d1,extrt        ; starting sector # of ext partition
  637. dbpbx:    bsr    fdnxt            ; find next logical drive
  638.     tst.b    d0            ; found any?
  639.     beq.s    dbpba            ; no logical drive found
  640.     bmi.s    dbpb2            ; error returned
  641.     cmpi.b    #5,d0            ; extended volume?
  642.     beq.s    dbpbx            ; if so, go find next logical drive
  643. dbpb1:    subq.w    #1,pbpb            ; partition that we want?
  644.     bpl.s    dbpb3            ; if not, continue the search
  645. dbpb2:    addq.l    #8,sp            ; else clean up stack
  646.     move.w    #0,bfat            ; assume partition has 12-bit fat
  647.     cmpi.b    #1,d0            ; 12-bit fat?
  648.     beq.s    dbpb22            ; if so, return
  649.     move.w    #1,bfat            ; else bflag = 1 for 16-bit fat
  650. dbpb22:    bra.s    dbpbr            ; and return
  651. dbpb3:    tst.b    ext            ; clun is in ext partition?
  652.     bne.s    dbpbx            ; if so, go find next ext vol
  653. dbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  654.     adda    #16,a0            ; index to next entry in pmap
  655.     dbra    d1,dbpb0
  656.     moveq    #0,d0            ; partition not found!
  657. dbpbr:    rts
  658.  
  659.     
  660. ;+
  661. ; fdpart - find a DOS partition.
  662. ;
  663. ; Passed:
  664. ;    a0 = address to partition entry
  665. ;
  666. ; Returns:
  667. ;    d0.b = 0        partition is not valid
  668. ;         = positive    #    partition is a valid partition
  669. ;           (this is the system indicator of the partition)
  670. ;    d1.l = starting sector # of a valid partition (if d0.b = 1 or 4)
  671. ;         = starting sector # of extended partition (if d0.b = 5)
  672. ;-
  673. fdpart:    tst.l    12(a0)            ; partition's size?
  674.     beq.s    fdp0            ; if =0, not valid
  675.  
  676.     move.b    4(a0),d0        ; d0 = system indicator
  677.     beq.s    fdpr            ; if =0, not valid
  678.  
  679.     cmpi.b    #4,d0            ; if =4, valid
  680.     beq.s    fdp1
  681.  
  682.     cmpi.b    #1,d0            ; if =1, valid
  683.     beq.s    fdp1
  684.  
  685.     cmpi.b    #5,d0            ; if =5, valid
  686.     beq.s    fdp1
  687.  
  688. fdp0:    moveq    #0,d0            ; else, not valid
  689.     bra.s    fdpr
  690.  
  691. fdp1:    move.l    8(a0),d1        ; d1.l = swapped starting sector #
  692.     ror.w    #8,d1            ; swap hi and lo byte of high word
  693.     swap    d1            ; swap hi and lo word
  694.     ror.w    #8,d1            ; swap hi and lo byte of low word
  695. fdpr:    rts
  696.  
  697.  
  698. ;+
  699. ; fdnxt - find a logical drive in the extended DOS partition
  700. ;
  701. ; Passed:
  702. ;    d0.b = (= 5 if a new extended volume was found)
  703. ;           (= 0 if nxtdrv was successful for last logical drive found)
  704. ;    d1.l = starting sector # of this extended volume
  705. ;    d2.b = count down for logical drive entries (if d0.b != 5)
  706. ;    a0.l = address of partition entry to be checked (if d0.b != 5)
  707. ;
  708. ; Assumes:
  709. ;    cpun = current physical unit #
  710. ;    extrt = starting sector # of extended DOS partition
  711. ;    extvol = offset from start of extended DOS partition (in sectors)
  712. ;
  713. ; Returns:
  714. ;    d0.b = 0        no logical drive found
  715. ;         = positive #    valid logical drive found
  716. ;           (this is the system indicator of the logical drive)
  717. ;         = negative #    error occured
  718. ;    d1.l = starting sector # of the logical drive (if d0.b = 1 or 4)
  719. ;         = starting sector # of next extended volume (if d0.b = 5)
  720. ;-
  721. fdnxt:    cmpi.b    #5,d0        ; new extended volume found?
  722.     bne.s    fdnxt0        ; if not, search for one
  723.     move.w    #1,-(sp)    ; return media change if detected
  724.     move.w    cpun,-(sp)    ; physical unit number
  725.     move.l    _dskbufp,-(sp)    ; buffer to read into
  726.     move.w    #1,-(sp)    ; read in 1 sector
  727.     move.l    d1,-(sp)    ; from beginning of extended volume
  728.     bsr    pread        ; pread(sectno, cnt, buf, phys#, flag)
  729.     adda    #14,sp        ; cleanup stack
  730.     tst.w    d0        ; pread successful?
  731.     bne    fdnxtr        ; if so, return
  732.     
  733.     movea.l    _dskbufp,a0    ; else, 
  734.     cmpi.w    #SIG,DOSSIG(a0)    ; boot record valid?
  735.     bne.s    fdnxtr        ; if not, return no drive found
  736.                 ; (d0 already set by pread)
  737.     adda.w    #DOSPM-16,a0    ; a0 = ptr to 1st entry in log drive map
  738.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  739.  
  740. fdnxt0:    subq.w    #1,d2        ; more entries to search?
  741.     bmi.s    fdnxt1        ; if not, return
  742.  
  743.     adda    #16,a0        ; a0 = ptr to entry to be examined
  744.     tst.l    12(a0)        ; partition size's?
  745.     beq.s    fdnxt0        ; if =0, not valid
  746.  
  747.     move.b    4(a0),d0    ; d0 = system indicator
  748.     beq.s    fdnxt0        ; if =0, not valid
  749.  
  750.     move.l    8(a0),d1    ; d1.l = logical start sector of drv or vol
  751.     beq.s    fdnxt0        ; if =0, not valid
  752.     ror.w    #8,d1        ; swap hi and lo byte of high word
  753.     swap    d1        ; swap hi and lo word
  754.     ror.w    #8,d1        ; swap hi and lo byte of low word
  755.  
  756.     cmpi.b    #4,d0        ; if =4,
  757.     beq.s    fdnxt2        ; valid logical drive found
  758.  
  759.     cmpi.b    #1,d0        ; if =1,
  760.     beq.s    fdnxt2        ; valid logical drive found
  761.  
  762.     cmpi.b    #5,d0        ; if =5, valid ptr to next ext volume
  763.     bne.s    fdnxt0        ; else, not valid
  764.     move.l    d1, extvol    ; offset of ext vol from start of ext DOS
  765.     bra.s    fdnxt3
  766.  
  767. fdnxt1:    moveq    #0,d0        ; return no drive found
  768.     bra.s    fdnxtr
  769.  
  770. fdnxt2:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  771. fdnxt3:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  772. fdnxtr:    rts
  773.  
  774.  
  775. ;
  776. ;+
  777. ; gembpb - find the GEMDOS partition that corresponds to the requested
  778. ;       logical drive.
  779. ; Passed:
  780. ;    a0 = buffer address for root sector
  781. ;    d1 = number of entries in partition map
  782. ;
  783. ; Assumed:
  784. ;    pbpbs = partition being looked for
  785. ;
  786. ; Returns:
  787. ;    d0.b = 0        if partition not found
  788. ;         = negative #    some kind of error
  789. ;         = positive #    system indicator of the partition
  790. ;    d1.l = starting sector of the partition (if it is found)
  791. ;-
  792. gembpb:    adda.w    #HDSIZ,a0        ; a0 = ptr to hard disk size
  793.     tst.l    (a0)+            ; size? (a0 = ptr to start of pmap)
  794.     beq.s    gbpb4            ; if =0, no drive will exist
  795. gbpb0:    movem.l    d1/a0,-(sp)        ; save count and offset
  796.     sf    ext            ; not dealing with ext partition
  797.     bsr    fgpart            ; find partitions
  798.     tst.b    d0            ; found any?
  799.     beq.s    gbpba            ; not a valid partition
  800.     cmpi.b    #'X',d0            ; extended partition?
  801.     bne.s    gbpb1            ; if not, it's a regular partition
  802.     st    ext            ; else, it's an extended partition
  803.     move.l    #0,extvol        ; offset from start of partition = 0
  804.     move.l    d1,extrt        ; starting sector # of ext partition
  805. gbpbx:    bsr    fgnxt            ; find next logical drive
  806.     tst.b    d0            ; found any?
  807.     beq.s    gbpba            ; no logical drive found
  808.     bmi.s    gbpb2            ; error returned
  809.     cmpi.b    #'X',d0            ; extended volume?
  810.     beq.s    gbpbx            ; if so, go find next logical drive
  811. gbpb1:    subq.w    #1,pbpb            ; partition that we want?
  812.     bpl.s    gbpb3            ; if not, continue the search
  813. gbpb2:    addq.l    #8,sp            ; else BINGO!  Clean up stack
  814.     bra.s    gbpbr            ; and return
  815. gbpb3:    tst.b    ext            ; clun is in ext partition?
  816.     bne.s    gbpbx            ; if so, go find next ext vol
  817. gbpba:    movem.l    (sp)+,d1/a0        ; restore count and offset
  818.     adda    #12,a0            ; index to next entry in pmap
  819.     dbra    d1,gbpb0
  820. gbpb4:    moveq    #0,d0            ; partition not found!
  821. gbpbr:    rts
  822.  
  823.  
  824. ;+
  825. ; fgpart - find a GEMDOS partition.
  826. ;
  827. ; Passed:
  828. ;    a0 = address to partition entry
  829. ;
  830. ; Returns:
  831. ;    d0.b = 0        partition is not valid
  832. ;         = positive    #    partition is a valid partition
  833. ;           (this is the first byte in p_id of the partition)
  834. ;    d1.l = starting sector # of a valid partition (if d0.b = 'G' or 'B')
  835. ;         = starting sector # of extended partition (if d0.b = 'X')
  836. ;-
  837. fgpart:    tst.b    (a0)            ; check the valid partition flag
  838.     beq.s    fgp2            ; if =0, not valid
  839.  
  840.     tst.l    8(a0)            ; partition's size?
  841.     beq.s    fgp2            ; if =0, not valid
  842.  
  843.     cmpi.b    #'G',1(a0)        ; must find GEM as type
  844.     bne.s    fgp0            ; for REGULAR partition
  845.     cmpi.b    #'E',2(a0)        ; (ie., partition < 16Mb)
  846.     bne.s    fgp0
  847.     cmpi.b    #'M',3(a0)
  848.     beq.s    fgp3
  849.  
  850. fgp0:    cmpi.b    #'B',1(a0)        ; must find BGM as type
  851.     bne.s    fgp1            ; for BIG partition
  852.     cmpi.b    #'G',2(a0)        ; (ie., partition >= 16Mb)
  853.     bne.s    fgp1
  854.     cmpi.b    #'M',3(a0)
  855.     beq.s    fgp3
  856.  
  857. fgp1:    cmpi.b    #'X',1(a0)        ; or find XGM as type
  858.     bne.s    fgp2            ; for EXTENDED GEMDOS 
  859.     cmpi.b    #'G',2(a0)        ; partition
  860.     bne.s    fgp2            ; (ie., partition with
  861.     cmpi.b    #'M',3(a0)        ;  a linked list of
  862.     beq.s    fgp3            ;  logical drives)
  863.  
  864. fgp2:    moveq    #0,d0            ; else, not valid
  865.     bra.s    fgpr
  866.  
  867. fgp3:    move.l    4(a0),d1        ; d1.l = starting sector #
  868.     move.b    1(a0),d0        ; d0.b = first byte of p_id
  869. fgpr:    rts
  870.  
  871.  
  872. ;+
  873. ; fgnxt - find a logical drive in the extended GEMDOS partition
  874. ;
  875. ; Passed:
  876. ;    d0.b = (= 'X' if a new extended volume was found)
  877. ;           (= 0 if nxtdrv was successful for last logical drive found)
  878. ;    d1.l = starting sector # of this extended volume
  879. ;    d2.b = count down for logical drive entries (if d0.b != 'X')
  880. ;    a0.l = address of partition entry to be checked (if d0.b != 'X')
  881. ;
  882. ; Assumes:
  883. ;    cpun = current physical unit #
  884. ;    extrt = starting sector # of extended GEMDOS partition
  885. ;    extvol = offset from start of extended GEMDOS partition (in sectors)
  886. ;
  887. ; Returns:
  888. ;    d0.b = 0        no logical drive found
  889. ;         = positive #    valid logical drive found
  890. ;           (this is the first byte of p_id of the logical drive)
  891. ;         = negative #    error occured
  892. ;    d1.l = starting sector # of the logical drive (if d0.b = 'G' or 'B')
  893. ;         = starting sector # of next extended volume (if d0.b = 'X')
  894. ;-
  895. fgnxt:    cmpi.b    #'X',d0        ; new extended volume found?
  896.     bne.s    fgnxt0        ; if not, search for one
  897.     move.w    #1,-(sp)    ; return media change if detected
  898.     move.w    cpun,-(sp)    ; physical unit number
  899.     move.l    _dskbufp,-(sp)    ; buffer to read into
  900.     move.w    #1,-(sp)    ; read in 1 sector
  901.     move.l    d1,-(sp)    ; from beginning of extended volume
  902.     bsr    pread        ; pread(sectno, cnt, buf, phys#, flag)
  903.     adda    #14,sp        ; cleanup stack
  904.     tst.w    d0        ; pread successful?
  905.     bne    fgnxtr        ; if not, return error
  906.  
  907.     movea.l    _dskbufp,a0    ; a0 = ptr to partition map
  908.     adda.w    #HDSIZ+4-12,a0    ; a0 = ptr to 1st entry in log drive map
  909.     move.w    #MAXNPART+1,d2    ; d2 = count for # of log drive entries
  910.  
  911. fgnxt0:    subq.w    #1,d2        ; more entries to search?
  912.     bmi.s    fgnxt3        ; if not, return
  913.  
  914.     adda    #12,a0        ; a0 = ptr to entry to be examined
  915.     tst.l    8(a0)        ; partition size's?
  916.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  917.  
  918.     tst.b    (a0)        ; check the valid partition flag
  919.     beq.s    fgnxt0        ; if =0, not valid.  Try next entry
  920.  
  921.     move.l    4(a0),d1    ; d1.l = logical start sector of drv or vol
  922.  
  923.     cmpi.b    #'G',1(a0)    ; must find GEM as type
  924.     bne.s    fgnxt1        ; for REGULAR partition
  925.     cmpi.b    #'E',2(a0)    ; (ie., partition < 16Mb)
  926.     bne.s    fgnxt1
  927.     cmpi.b    #'M',3(a0)
  928.     beq.s    fgnxt4
  929.  
  930. fgnxt1:    cmpi.b    #'B',1(a0)    ; must find BGM as type
  931.     bne.s    fgnxt2        ; for BIG partition
  932.     cmpi.b    #'G',2(a0)    ; (ie., partition >= 16Mb)
  933.     bne.s    fgnxt2
  934.     cmpi.b    #'M',3(a0)
  935.     beq.s    fgnxt4
  936.  
  937. fgnxt2:    cmpi.b    #'X',1(a0)    ; or find XGM as type
  938.     bne.s    fgnxt3        ; for EXTENDED GEMDOS 
  939.     cmpi.b    #'G',2(a0)    ; partition
  940.     bne.s    fgnxt3        ; (ie., partition with
  941.     cmpi.b    #'M',3(a0)    ;  a linked list of
  942.     bne.s    fgnxt0        ;  logical drives)
  943.  
  944.     move.l    d1, extvol    ; offset of ext vol from start of ext GEMDOS
  945.     bra.s    fgnxt5
  946.  
  947. fgnxt3:    moveq    #0,d0        ; return no drive found
  948.     bra.s    fgnxtr
  949.  
  950. fgnxt4:    add.l    extvol,d1    ; d1 = start sector wrt beginning of ext DOS
  951. fgnxt5:    add.l    extrt,d1    ; d1 = start sector wrt beginning of disk
  952.     move.b    1(a0),d0    ; d0.b = first byte of p_id
  953. fgnxtr:    rts
  954.  
  955.  
  956. ;
  957. ;--------------
  958. ;
  959. ; getbpb(dev, sectorno)
  960. ; WORD dev;        4(sp).w
  961. ; LONG sectorno;    6(sp).l
  962. ;
  963. ; Assume -
  964. ;    cpun contains physical unit number of dev
  965. ;
  966. getbpb:    move.w    #1,-(sp)        ; return media change if detected
  967.     move.w    cpun,-(sp)        ; physical unit
  968.     move.l    _dskbufp,-(sp)        ; buffer
  969.     move.w    #1,-(sp)        ; 1 sector
  970.     move.l    $10(sp),-(sp)        ; sector # of boot sector
  971.     bsr    pread            ; pread(bootsect, 1, buf, phys#, flag)
  972.     adda    #14,sp            ; clean up stack
  973.     tst.w    d0            ; any trouble reading?
  974.     beq.s    getb0            ; if no, go on normally
  975.     cmpi.w    #EREADF,d0        ; was it a read error?
  976.     beq.s    getb9            ; if it is, retry
  977.     cmpi.w    #EDRVNR,d0        ; was it drive not ready?
  978.     bne    getb8            ; if not, return
  979.                     ; else let user retry
  980. getb9:    move.w    4(sp),d1        ; d1 = drive # excluding A: and B:
  981.     bsr    critic
  982.     cmpi.l    #CRITRETRY,d0        ; retry?
  983.     bne    getb7            ; if not, return
  984.     bra.s    getbpb            ; else read again
  985.  
  986. getb0:    movea.l    _dskbufp,a0        ; a0 = ptr to boot sector image
  987.     movea.l    #bpbs,a2        ; a2 = ptr to bpb
  988.  
  989.     move.w    #$0b,d0
  990.     bsr    getlhw
  991.     cmp.w    maxssz,d0        ; is sector size too big?
  992.     bhi    getb7            ; if it is, can't handle it
  993.     move.w    d0,(a2)+        ; =byt/sec
  994.     beq    getb7            ; if =0, bad data
  995.     move.w    d0,d1
  996.     divu    #512,d0            ; d0.b = ratio log : phys sector size
  997.     move.w    d0,sizr            ; save the ratio
  998.  
  999.     clr.w    d0
  1000.     move.b    $d(a0),d0
  1001.     move.w    d0,(a2)+        ; =sec/cluster
  1002.     beq    getb7            ; if =0, bad data
  1003.  
  1004.     mulu    d1,d0
  1005.     move    d0,(a2)+        ; =byt/cluster
  1006.  
  1007.     move    #$11,d0
  1008.     bsr    getlhw            ; number of directory entries
  1009.     tst    d0            ; num o' entries ?= 0
  1010.     beq    getb7            ; if so, bad data
  1011.     mulu    #32,d0            ; size of each entry
  1012.     divu    d1,d0            ; number of sectors required
  1013.     move.l    d0,d1
  1014.     swap    d1
  1015.     tst    d1
  1016.     beq.s    getb1
  1017.     addq    #1,d0            ; round up
  1018. getb1:    move    d0,(a2)+        ; =rdlen
  1019.     move    d0,d2
  1020.  
  1021.     move    #$16,d0
  1022.     bsr    getlhw
  1023.     move    d0,(a2)+        ; =FATsize
  1024.     beq    getb7            ; if =0, bad data
  1025.     move    d0,d1
  1026.     move    d0,fsiz            ; save FAT size
  1027.  
  1028.     move    #$e,d0
  1029.     bsr    getlhw            ; number of reserved sectors
  1030.     add    d1,d0
  1031.     move    d0,(a2)+        ; =2nd FAT start
  1032.     move    d0,fatrec        ; save 2nd FAT start 
  1033.  
  1034.     add    d1,d0            ; plus size of second fat
  1035.     add    d2,d0            ; plus rdlen
  1036.     move    d0,(a2)+        ; = data start
  1037.     move    d0,d2            ; save start of data
  1038.  
  1039.     move    #$13,d0
  1040.     bsr    getlhw            ; number of sectors on media
  1041.     sub    d2,d0            ; subtract # used by FATs,dir,boot
  1042.     beq    getb7            ; if =0, bad data
  1043.     clr.l    d1
  1044.     move    d0,d1
  1045.     clr    d0
  1046.     move.b    $d(a0),d0        ; number of sectors/cluster
  1047.     divu    d0,d1            ; rounding down
  1048.     move    d1,(a2)+        ; =number of clusters
  1049.     move    bfat,(a2)        ; =flags, 12 or 16 bit fats
  1050.  
  1051.     move.w    sizr,d2            ; d2 = current sector size ratio
  1052.     lea    sratio,a1        ; a1 = ptr to sector size ratio table
  1053.     move.w    4(sp),d0        ; d0 = drive number
  1054.     move.b    d2,(a1,d0.w)        ; update sector size ratio in table
  1055.  
  1056.     move.w    cpun,d1            ; d1 = physical unit #
  1057.     btst.b    d1,rmbits        ; is unit removable?
  1058.     beq    getb6            ; if not, can skip the fat checksum
  1059.  
  1060.     lea    serno,a1        ; a1 = ptr to table of serial #s
  1061.     mulu.w    #SERLEN,d0        ; dev# * SERLEN to index into table
  1062.     adda.l    d0,a1            ; a1 = ptr to serial # of dev
  1063.     move.w    #SERLEN-1,d1        ; length of serial # - 1
  1064. getb2:    move.b    $8(a0,d1.w),(a1,d1.w)    ; update serial # of dev
  1065.     dbra    d1,getb2
  1066.  
  1067.     lea    fatsum,a2        ; a2 = ptr to FAT check sum table
  1068.     move.w    4(sp),d0        ; d0 = dev number
  1069.     mulu    #FATLEN,d0        ; d0*FATLEN = to index into table
  1070.     adda.l    d0,a2            ; a2 = ptr to FAT check sum tbl of dev
  1071.  
  1072.     move.w    fatrec,d0        ; d0 = log starting sector of 2nd FAT
  1073.     mulu    d2,d0            ; (in 512-byte sectors)
  1074.     movea.l    $6(sp),a1        ; a1 = starting sector of drive
  1075.     adda.l    d0,a1            ; a1 = phys starting sector of 2nd FAT
  1076.  
  1077.     move.w    fsiz,d1            ; d1 = # FAT sectors to read
  1078.     subq.l    #1,d1            ;    = FAT size - 1
  1079.  
  1080. getb3:    move.w    sizr,d2            ; d2 = count per FAT sector
  1081.     subq.w    #1,d2
  1082.      clr.l    temp            ; initialize the sum
  1083. getb4:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1084.     move.w    #1,-(sp)        ; return media change if detected
  1085.     move.w    cpun,-(sp)        ; physical unit
  1086.     move.l    a0,-(sp)        ; buffer (in _dskbufp)
  1087.     move.w    #1,-(sp)        ; read 1 phys sector
  1088.     move.l    a1,-(sp)        ; from sector a1
  1089.     bsr    pread            ; pread()
  1090.     adda    #14,sp            ; clean up stack
  1091.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1092.     tst.w    d0            ; pread successful?
  1093.     beq    getb5            ; if so, go on normally
  1094.     cmpi.w    #EREADF,d0        ; read error?
  1095.     beq.s    getba            ; if so, retry
  1096.     cmpi.w    #EDRVNR,d0        ; drive not ready?
  1097.     bne    getb8            ; if not, return
  1098.  
  1099. getba:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers
  1100.     move.w    24(sp),d1        ; d1 = drive # excluding A: and B:
  1101.     bsr    critic            ; critical error handler
  1102.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers
  1103.     cmpi.l    #CRITRETRY,d0        ; retry?
  1104.     beq.s    getb4            ; if so, try again
  1105.     bra    getb7            ; else return
  1106.  
  1107. getb5:    bsr    bsum            ; add up values in the sector
  1108.     addq    #1,a1            ; get ready for next sector
  1109.     dbra    d2,getb4        ; until one logical FAT sector is done
  1110.  
  1111.     bsr    csum            ; find the checksum
  1112.     move.b    d0,(a2)+        ; update checksum for this FAT sector
  1113.     dbra    d1,getb3        ; until all sectors are checked
  1114.  
  1115. getb6:    move.w    $4(sp),d0        ; d0 = dev number
  1116.     lea    mcflgs,a0        ; load address of mcflgs table
  1117.     clr.b    (a0,d0.w)        ; clear mcflg for dev
  1118.  
  1119.     lea    xst,a0            ; a0 = ptr to drive existence table
  1120.     move.b    #2,(a0,d0.w)        ; dev definitely exists
  1121.  
  1122.     lea    fatst,a0        ; a0 = ptr to FAT start sector table
  1123.     asl.w    #1,d0            ; offset = dev# * 2 (tbl of words)
  1124.     move    fatrec,(a0,d0.w)    ; update FAT starting sect#
  1125.  
  1126.     lea    fatend,a0        ; a0 = ptr to FAT end sector table
  1127.     move.w    fatrec,d1        ; d1 = fatend(dev)
  1128.     add.w    fsiz,d1            ;    = fatrec + fsiz - 1
  1129.     subq.w    #1,d1    
  1130.     move.w    d1,(a0,d0.w)        ; fatend(dev) = fatrec + fsiz - 1
  1131.  
  1132.     lea    start,a0        ; a0 = ptr to beginning of start table
  1133.     asl.w    #1,d0            ; offset = dev# * 2 * 2 (tbl of longs)
  1134.     move.l    $6(sp),(a0,d0.w)    ; update starting sect# of dev
  1135.  
  1136.     move.l    #bpbs,d0        ; no errors, return ptr to BPB
  1137.     bra.s    getb8            ; return
  1138.  
  1139. getb7:    moveq    #-1,d0            ; error
  1140. getb8:    rts
  1141.  
  1142.  
  1143. ;+
  1144. ; WORD getlhw(d0=offset)
  1145. ; returns word (low,high) from 0(D0,A0)
  1146. ;-
  1147.  
  1148. getlhw:    move    d1,-(sp)        ; preserve d1
  1149.     move.b    1(a0,d0.w),d1
  1150.     lsl.w    #8,d1
  1151.     move.b    0(a0,d0.w),d1
  1152.     move    d1,d0
  1153.     move    (sp)+,d1
  1154.     rts
  1155.  
  1156.  
  1157. ;+
  1158. ; bsum
  1159. ;
  1160. ; Passed:
  1161. ;    a0 = starting address of buffer to be summed
  1162. ;    temp.l = current sum
  1163. ;
  1164. ; Function:
  1165. ;      - sum up 512 bytes of a buffer 4 bytes at a time
  1166. ;    - save the sum in temp.l
  1167. ;
  1168. ; Algorithm for check summing the FAT:
  1169. ;    - add up bytes in the buffer 4 bytes at a time    (in bsum)
  1170. ;    - if the sum is non-zero, EOR the high word     (in csum)
  1171. ;      with the low word of the 4-byte result
  1172. ;    - now take this 2-byte result, and EOR its high    (in csum)
  1173. ;      byte with its low byte to get the final 1-byte
  1174. ;      result
  1175. ;-
  1176. bsum:    movem.l    d1/a0,-(sp)        ; save d1, a0
  1177.     move.l    temp,d0            ; d0 = current sum
  1178.     move    #127,d1            ; count
  1179. bsum0:    add.l    (a0)+,d0        ; add 4 bytes to sum
  1180.     dbra    d1,bsum0        ; until all bytes are added
  1181.     move.l    d0,temp            ; temp.l = new sum
  1182.     movem.l    (sp)+,d1/a0        ; restore d1, a0
  1183.     rts
  1184.  
  1185.  
  1186. ;+
  1187. ; csum
  1188. ; (a) EOR the high word with the low word of temp.l
  1189. ; (b) then EOR the high byte with the low byte of result of (a)
  1190. ;
  1191. ; Returns:
  1192. ;    d0.b = checksum
  1193. ;-
  1194. csum:    move.w    temp+2,d0        ; d0.w = low word of result
  1195.     eor.w    d0,temp            ; exclusive-or low and high word
  1196.     move.b    temp+1,d0        ; d0.b = low byte of xor-ed result
  1197.     eor.b    d0,temp            ; exclusive-or low and high byte
  1198.     move.b    temp,d0
  1199.     rts                ; d0.b = checksum
  1200.  
  1201.  
  1202. ;
  1203. ;----------------
  1204. ;
  1205. ;  Read/Write sectors
  1206. ;
  1207. ;    Synopsis:    _ahdi_rw(rw, buf, count, recno, dev, lrecno)
  1208. ;        WORD rw        4(sp).w        ; non-zero -> write
  1209. ;        char buf    6(sp).l
  1210. ;        WORD count    $a(sp).w
  1211. ;        WORD recno    $c(sp).w
  1212. ;        WORD dev    $e(sp).w
  1213. ;        WORD lrecno    $10(sp).l    ; optional
  1214. ;-
  1215.  
  1216. ; stack frame offsets
  1217. xrw    equ    8
  1218. xbuf    equ    10
  1219. xcount    equ    14
  1220. xrecno    equ    16
  1221. xdev    equ    18
  1222. xlrecno    equ    20
  1223.  
  1224. _sasi_rw:
  1225. _ahdi_rw:
  1226.     link    a6,#0            ; create a frame pointer
  1227.     subq.w    #2,xdev(a6)        ; drive # excluding A: and B:
  1228.     move.w    xrw(a6),d0        ; r/w and flags word
  1229.     andi.b    #$a,d0            ; phys op?  ignore media change?
  1230.     bne    ahrw1            ; yes, go ahead and do r/w
  1231.                     ; else check for media change
  1232.     lea    sratio,a1        ; a1 = ptr to sector size ratio table
  1233.     adda.w    xdev(a6),a1        ; a1 = ptr to dev's sector size ratio
  1234.     move.b    (a1),sizr+1        ; sizr = current sector size ratio
  1235.                     ;     (coerced to word)
  1236.     lea    mcflgs,a0        ; a0 = ptr to mcflgs of drive
  1237.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1238.     move.b    (a0),d0            ; d0 = mcflg of dev
  1239.     beq    ahrw1            ; if media definitely not, go do r/w
  1240.  
  1241.     cmpi.b    #2,d0            ; is media definitely changed?
  1242.     beq    retmc            ; if yes, return media has changed
  1243.  
  1244.     sf    mcrw            ; mcrw = FALSE
  1245.     lea    pun,a1            ; a1 = ptr to pun table
  1246.     adda.w    xdev(a6),a1        ; a1 = ptr to pun dev belongs to
  1247.     move.b    (a1),cpun+1        ; cpun = pun of dev
  1248.  
  1249. chkmc:    lea    start,a1        ; a1 = ptr to start table
  1250.     move.w    xdev(a6),d0        ; d0 = drive #
  1251.     add.w    d0,d0            ; d0*2*2 (index into tbl of longs)
  1252.     add.w    d0,d0
  1253.     movea.l    (a1,d0.w),a1        ; a1 = dev starting sector
  1254.  
  1255.     move.w    #1,-(sp)        ; return media change if detected
  1256.     move.w    cpun,-(sp)        ; physical unit number
  1257.     move.l    _dskbufp,-(sp)        ; buffer
  1258.     move.w    #1,-(sp)        ; 1 sector
  1259.     move.l    a1,-(sp)        ; dev starting sector
  1260.     bsr    pread            ; try to read dev's boot sector
  1261.     adda    #14,sp            ; clean up stack
  1262.     tst.w    d0            ; pread successful?
  1263.     beq.s    chkser            ; yes, go check serial number
  1264.  
  1265.     cmpi.w    #E_CHNG,d0        ; media change detected?
  1266.     bne.s    rderr1            ; if not, assume it's read error
  1267.  
  1268. mcchg:    move.b    #1,d0            ; d0.b = 1 (may be changed)
  1269.     move.w    xdev(a6),d1        ; d1.w = drive # excluding A: and B:
  1270.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1271.     bsr    s_mc_xst        ; set mcflgs and xst flags for all dev
  1272.     bra.s    chkmc            ; then try again
  1273.  
  1274. rderr1:    move.w    xdev(a6),d1        ; device number
  1275.     bsr    critic            ; call critical error handler
  1276.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1277.     beq.s    chkmc            ; if yes, go back and try it
  1278.     bra    ahrw7            ; else return
  1279.  
  1280. chkser:    lea    serno,a1        ; a1 = ptr to serial #s table
  1281.     move.w    xdev(a6),d0        ; d0 = dev number
  1282.     mulu.w    #SERLEN,d0        ; *SERLEN for index into table
  1283.     adda.l    d0,a1            ; a1 = ptr to serial # of dev
  1284.  
  1285.     move.l    _dskbufp,a2        ; a2 = ptr to buffer
  1286.     addq.w    #8,a2            ; a2 = ptr to serial # read
  1287.      move.w    #SERLEN-1,d0        ; d0 = count for comparison
  1288. cmpser:    cmpm.b    (a2)+,(a1)+        ; serial # read ?= serial # recorded
  1289.     bne    ismc            ; no, media has changed
  1290.     dbra    d0,cmpser        ; compare next byte of serial #
  1291.                     ; serial # hasn't changed, try FAT
  1292.     move.w    xdev(a6),d0        ; d0 = dev number
  1293.     lea    fatsum,a1        ; a1 = ptr to fat checksum table
  1294.     move.w    #FATLEN,d1        ; d1.w = index into table
  1295.     mulu    d0,d1
  1296.     adda.l    d1,a1            ; a1 = ptr to fat checksum of dev
  1297.  
  1298.     add.w    d0,d0            ; d0*2 = index into table of words
  1299.     lea    fatst,a2        ; a2 = ptr to FAT start table
  1300.     move.w    (a2,d0.w),fatrec    ; fatrec = fatst(dev)
  1301.  
  1302.     lea    fatend,a2        ; a2 = ptr to FAT end table
  1303.     move.w    (a2,d0.w),d1        ; d1 = counter to scan FAT table
  1304.     sub.w    fatrec,d1        ;    = fatend(dev) - fatst(dev)
  1305.  
  1306.     lea    start,a2        ; a2 = ptr to start table
  1307.     add.w    d0,d0            ; d0*2*2 = index into table of longs
  1308.     movea.l    (a2,d0.w),a2        ; a2 = start sector of dev
  1309.     move.w    fatrec,d2        ; d2 = fatst(dev)
  1310.     mulu    sizr,d2            ; d2 = fatst(dev) in 512-byte sector
  1311.     adda.l    d2,a2            ; a2 = phys start sector of 2nd FAT
  1312.  
  1313.     movea.l    _dskbufp,a0        ; a0 = ptr to buffer
  1314. cmpfat:    move.w    sizr,d2            ; d2 = # reads per FAT sector
  1315.     subq.w    #1,d2            ; d2 - 1 = counter
  1316.     clr.l    temp            ; initialize sum
  1317. cfat0:    movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a1, a2
  1318.     move.w    #1,-(sp)        ; return media change if detected
  1319.     move.w    cpun,-(sp)        ; physical unit number
  1320.     move.l    a0,-(sp)        ; buffer
  1321.     move.w    #1,-(sp)        ; 1 sector
  1322.     move.l    a2,-(sp)        ; at sector a2
  1323.     bsr    pread            ; try to read this FAT sector
  1324.     adda    #14,sp            ; clean up stack
  1325.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, a0, a1, a2
  1326.     tst.w    d0            ; pread successful?
  1327.     beq.s    chkfat            ; if yes, go check sum FAT sectors
  1328.                     ; else check if it's media change
  1329.     cmpi.w    #E_CHNG,d0        ; media change detected?
  1330.     beq    mcchg            ; if so, go test media change again
  1331.                     ; else assume it's read error
  1332.     movem.l    d1-d2/a0-a2,-(sp)    ; save registers d1, d2, a0, a2
  1333.     move.w    xdev(a6),d1        ; drive number
  1334.     bsr    critic
  1335.     movem.l    (sp)+,d1-d2/a0-a2    ; restore registers d1, d2, a0, a2
  1336.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1337.     beq.s    cfat0            ; if yes, go back and try it
  1338.     bra    ahrw7            ; else return
  1339.  
  1340. chkfat:    bsr    bsum            ; if ok, sum the sector
  1341.     addq    #1,a2            ; ready for try next sector
  1342.     dbra    d2,cfat0        ; until one FAT sector is summed
  1343.  
  1344.     bsr    csum            ; find the checksum
  1345.     cmp.b    (a1)+,d0        ; checksum recorded ?= checksum found
  1346.     bne    ismc            ; if no match, media has changed
  1347.     dbra    d1,cmpfat        ; until all sectors are checked
  1348.  
  1349.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  1350.     adda.w    xdev(a6),a0        ; a0 = ptr to mcflg of drive
  1351.     clr.b    (a0)            ; clear mcflg for dev
  1352.  
  1353. ahrw1:    tst.w    xcount(a6)        ; any sector to r/w?
  1354.     beq    ahrw6            ; if =0, done
  1355.  
  1356.     cmpi.w    #-1,xrecno(a6)        ; does recno = -1?
  1357.     bne.s    ahrw9            ; if not, we have a word record #
  1358.     move.l    xlrecno(a6),a1        ; a1.l = start record #
  1359.     bra.s    ahrwa
  1360. ahrw9:    moveq    #0,d0            ; coerce to long
  1361.     move.w    xrecno(a6),d0        ; d0.l = recno
  1362.     movea.l    d0,a1            ; a1.l = start record #
  1363.  
  1364. ahrwa:    move.l    a1,strec        ; save first sector to r/w
  1365.     moveq    #0,d1            ; coerce to long
  1366.     move.w    xcount(a6),d1        ; d1.l = #sectors to r/w
  1367.     adda.l    d1,a1            ; a1.l = last sector to r/w
  1368.     subq.w    #1,a1            ;      = first sector + count - 1
  1369.     move.l    a1,endrec        ; save last sector to r/w
  1370.     move.l    xbuf(a6),stbuf        ; save starting buffer address
  1371.  
  1372.     move.l    strec,d1        ; d1.l = starting sector to r/w
  1373.     moveq    #0,d2            ; clear d2
  1374.     move.w    xcount(a6),d2        ; d2.l = # sectors to r/w
  1375.     btst.b    #3,xrw+1(a6)        ; physical operation?
  1376.     bne.s    ahrwb            ; if so, go on
  1377.                     ; else log -> phys sector mapping
  1378.     mulu    sizr,d1            ; d1.l = phys start sector to r/w
  1379.     mulu    sizr,d2            ; d2.l = # phys 512-byte sects to r/w
  1380.  
  1381. ahrwb:    move.l    xbuf(a6),a1        ; a1.l = buffer addr to r/w
  1382.     cmpi.l    #MAXSECTORS,d2        ; more than one DMAfull?
  1383.     bgt.s    ahrwc            ; if so, only do one DMAfull
  1384.     move.w    d2,xcount(a6)        ; else xcount(a6) = # sects requested
  1385.     bra.s    ahrw2
  1386. ahrwc:    move.w    #MAXSECTORS,xcount(a6)    ; xcount(a6) = 1 DMAfull of sects
  1387. ahrw2:    btst    #0,xbuf+3(a6)        ; an odd boundary?
  1388.     beq.s    ahrw4            ; no, so do normally
  1389.  
  1390.     cmpi.w    #2,xcount(a6)        ; can only do 2 at a time tops this way
  1391.     ble.s    ahrw3
  1392.     move.w    #2,xcount(a6)
  1393.  
  1394. ahrw3:    move.l    _dskbufp,a1        ; use the bios buffer for this transfer
  1395.  
  1396.     btst    #0,xrw+1(a6)        ; is this a write?
  1397.     beq.s    ahrw4            ; no, so go fill buffer from disk
  1398.  
  1399.     movea.l    xbuf(a6),a2        ; source (a1.l = dest)
  1400.     move.w    xcount(a6),-(sp)    ; # sectors to be moved
  1401.     bsr    smove            ; move sectors from a2 to a1
  1402.     addq.l    #2,sp            ; clean up stack
  1403.  
  1404. ahrw4:    movem.l    d1-d2,-(sp)        ; save total count and start sector
  1405.     move.w    xdev(a6),-(sp)
  1406.     move.l    d1,-(sp)
  1407.     move.w    xcount(a6),-(sp)    ; count
  1408.     move.l    a1,-(sp)        ; buffer
  1409.     move.w    xrw(a6),-(sp)
  1410.     bsr    _do_rw
  1411.     adda    #14,sp
  1412.     movem.l    (sp)+,d1-d2        ; restore total count and start sector
  1413.     tst.l    d0            ; any errors there?
  1414.     beq.s    ahrw8            ; no, go on normally
  1415.  
  1416.     cmpi.l    #E_CHNG,d0        ; media change detected?
  1417.     bne    ahrw7            ; if not, give up
  1418.     st    mcrw            ; else it's mc returned when r/w
  1419.     bra    mcchg            ; and go check if media has changed
  1420.  
  1421. ahrw8:    btst    #0,xbuf+3(a6)        ; on odd boundary?
  1422.     beq.s    ahrw5            ; if not, go on normally
  1423.     btst    #0,xrw+1(a6)        ; was it a read?
  1424.     bne.s    ahrw5            ; if it wasn't, go on normally
  1425.                     ; else
  1426.     movea.l    xbuf(a6),a1        ; must move data read to desired dest
  1427.     movea.l    _dskbufp,a2        ; from dskbuf
  1428.     move.w    xcount(a6),-(sp)    ; # of sectors to move
  1429.     bsr    smove
  1430.     addq.l    #2,sp            ; clean up stack
  1431.  
  1432. ahrw5:    moveq    #0,d0            ; clear d0
  1433.     move.w    xcount(a6),d0        ; #sectors we did
  1434.     sub.l    d0,d2            ; #sectors left to do
  1435.     add.l    d0,d1            ; next starting sector to r/w
  1436.     asl.l    #8,d0            ; d0 = #bytes we did
  1437.     add.l    d0,d0            ;    = #sectors * 512
  1438.     add.l    d0,xbuf(a6)        ; buf += (sectors_done * sector size)
  1439.     tst.l    d2            ; anything left to r/w?
  1440.     bne    ahrwb            ; if so, continue
  1441.                     ; check if wrote to boot sector
  1442. chkwr:    move.w    xrw(a6),d0        ; d0 = r/w and flags word
  1443.     btst    #0,d0            ; was it a write?
  1444.     beq    ahrw6            ; if not, done
  1445.     btst    #3,d0            ; was it a physical operation?
  1446.     bne    ahrw6            ; if it was, done
  1447.     btst    #1,d0            ; ignore media change?
  1448.     bne.s    wrfat            ; if so, update FAT chksums if appl.
  1449.     tst.l    strec            ; wrote to boot sector?
  1450.     bne.s    wrfat            ; if not, update FAT chksums if appl.
  1451.     lea    mcflgs,a0        ; else, a0 = ptr to mcflgs table
  1452.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1453.     move.b    #2,(a0)            ; assume medium has changed
  1454.  
  1455. wrfat:    moveq    #0,d0            ; clear d0
  1456.     move.b    cpun+1,d0        ; d0.b = pun of dev
  1457.     btst.b    d0,rmbits        ; is drive removable?
  1458.     beq    ahrw6            ; if not, done
  1459.                     ; else check if wrote to FATs
  1460.     lea    fatend,a0        ; a0 = ptr to fatend table
  1461.     move.w    xdev(a6),d0        ; d0 = device number
  1462.     add.w    d0,d0            ; d0*2 = index into table of words
  1463.     moveq    #0,d1            ; coerce to long
  1464.     move.w    (a0,d0.w),d1        ; d1 = last FAT's ending sector
  1465.     cmp.l    strec,d1        ; wrote beyond the last FAT?
  1466.     blt    ahrw6            ; if so, done
  1467.  
  1468.     lea    fatst,a0        ; a0 = ptr to fatst table
  1469.     moveq    #0,d2            ; coerce to long
  1470.     move.w    (a0,d0.w),d2        ; d2 = last FAT's starting sector
  1471.     cmp.l    endrec,d2        ; wrote before the last FAT?
  1472.     bgt    ahrw6            ; if so, done
  1473.                     ; else update FAT sector checksums
  1474.     move.l    stbuf,a0        ; a0 = ptr to buffer w/ written data
  1475.     lea    fatsum,a1        ; a1 = ptr to start of fatsum table
  1476.     move.w    xdev(a6),d0        ; d0 = dev number
  1477.     mulu.w    #FATLEN,d0        ; d0 = offset to dev's FAT chksum
  1478.     adda.l    d0,a1            ; a1 = ptr to dev's first FAT chksum
  1479.     move.l    strec,d0        ; d0 = first sector wrote to
  1480.     sub.l    d2,d0            ; d0 = strec - start(last FAT)
  1481.     beq.s    wrfat2            ; if strec = start(last FAT), 
  1482.                     ;     no adjustments needed
  1483.      blt.s    wrfat1            ; if strec < start(last FAT)
  1484.                     ;     begin from start(last FAT)
  1485.     move.l    strec,d2        ; else begin from strec
  1486.     adda.l    d0,a1            ; a1 = ptr to fatsum to be updated
  1487.     bra.s    wrfat2
  1488.  
  1489. wrfat1:    neg.l    d0            ; d0 = index into stbuf
  1490.     asl.l    #8,d0            ;    = (start(last FAT) - strec)*512
  1491.     add.l    d0,d0
  1492.     adda.l    d0,a0            ; a0 = pt to addr of buf for update
  1493.  
  1494. wrfat2:    cmp.l    endrec,d1        ; if end(last FAT) <= endrec
  1495.     ble.s    wrfat3            ;     stop at end(last FAT)
  1496.     move.l    endrec,d1        ; else stop at endrec
  1497.  
  1498. wrfat3:    sub    d2,d1            ; d1 = # sectors to be processed
  1499. wrfat4:    move.w    sizr,d2            ; d2 = # phys sect per log sect
  1500.     subq.w    #1,d2            ; dbra likes one less
  1501.     clr.l    temp            ; initialize sum
  1502. wrfat5:    bsr    bsum            ; sum up one 512-byte sector
  1503.     adda.l    #512,a0            ; point to next 512 bytes
  1504.     dbra    d2,wrfat5        ; until one logical sector is done
  1505.     bsr    csum            ; obtain checksum
  1506.     move.b    d0,(a1)+        ; record new fat checksum
  1507.     dbra    d1,wrfat4        ; do until all are updated
  1508.  
  1509. ahrw6:    clr.l    d0            ; got here with no errors!
  1510.     bra.s    ahrw7
  1511.  
  1512. ismc:    tst.b    mcrw            ; media change returned by r/w?
  1513.     beq    onemc            ; no, only dev has changed
  1514.     move.b    #2,d0            ; d0.b = value to set to
  1515.     move.w    xdev(a6),d1        ; d1.w = dev number
  1516.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1517.     bsr    s_mc_xst        ; set mcflgs and xst flags for devs
  1518.     bra.s    retmc            ; return media change detected
  1519.  
  1520. onemc:    lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  1521.     adda.w    xdev(a6),a0        ; a0 = ptr to dev's mcflg
  1522.     move.b    #2,(a0)            ; set mcflg for dev to has changed
  1523.     lea    xst,a0            ; a0 = ptr to drive existence table
  1524.     adda.w    xdev(a6),a0        ; a0 = ptr to xst flag of dev
  1525.     move.b    #2,(a0)            ; assume dev exists
  1526.  
  1527. retmc:    move.l    #E_CHNG,d0        ; yes, return media change error
  1528. ahrw7:    unlk    a6
  1529.     rts
  1530.  
  1531.  
  1532. ;----------------
  1533. ;
  1534. ;  Copy unaligned sectors
  1535. ;  (this is *supposed* to be slow!)
  1536. ;
  1537. ;    Passed:    d2.w    = # of sectors (known to be 1 or 2)
  1538. ;        a2    -> source sector
  1539. ;        a1    -> dest buffer (oddly aligned)
  1540. ;
  1541. smove:    move.w    4(sp),d0        ; d0 = # 512-byte sectors to move
  1542.     asl.w    #8,d0            ; d0 * 512 = # bytes to move
  1543.     asl.w    #1,d0
  1544.     subq.w    #1,d0            ; dbra likes one less
  1545. smove1:    move.b    (a2)+,(a1)+
  1546.     dbra    d0,smove1
  1547.     rts
  1548.  
  1549.  
  1550. ;
  1551. ;+
  1552. ; _do_rw - called to read/write no more than 128K to an even boundary
  1553. ;
  1554. ; Passed:    dev    $10(sp).W
  1555. ;        recno    $c(sp).L
  1556. ;        count    $a(sp).W
  1557. ;        buf    6(sp).L
  1558. ;        rw    4(sp).W        ; non-zero -> write
  1559. ;
  1560. ;-
  1561. _do_rw:
  1562.     move.w    d3,-(sp)        ; preserve d3
  1563.  
  1564. sasrw0:    move.w    _retries,retrycnt    ; setup retry counter
  1565.  
  1566.     move.w    6(sp),d3        ; rw
  1567.     btst    #2,d3            ; are retries disabled?
  1568.     beq.s    sasrw1            ; no, act normally
  1569.     move.w    #0,retrycnt        ; yes, so set retrycnt to zero
  1570.  
  1571. sasrw1:    lea    2(sp),a1        ; frame pointer
  1572.     move.l    $c(a1),d0        ; sect.L
  1573.     move.w    4(a1),d3        ; rw
  1574.  
  1575.     btst    #3,d3            ; physical unit operation
  1576.     beq.s    sasrw2            ; no, so do log->phys mapping
  1577.  
  1578.     move    $10(a1),cpun        ; get unit number
  1579.     bra.s    sasrw3            ; and use that as the physical unit
  1580.  
  1581. sasrw2:    clr    d2            ; coerce byte to word
  1582.     move.w    $10(a1),d1        ; get device
  1583.      lea    pun,a2
  1584.     move.b    (a2,d1.w),cpun+1    ; get physical unit number
  1585. sasrw3:    move.w    cpun,-(sp)        ; dev
  1586.     move.l    6(a1),-(sp)        ; buf
  1587.     move.w    $a(a1),-(sp)        ; count
  1588.  
  1589.     btst    #3,d3            ; physical operation?
  1590.     bne.s    sasrw4            ; yes, so no offset
  1591.  
  1592.     add.w    d1,d1            ; d1*2*2 = index into table of longs
  1593.     add.w    d1,d1
  1594.     lea    start,a2
  1595.     add.l    (a2,d1.w),d0        ; adjust sector number
  1596.  
  1597. sasrw4:    move.l    d0,-(sp)        ; sect
  1598.     btst    #0,d3            ; read or write?
  1599.     bne.s    sasrw5            ; (write)
  1600.     bsr    _hread            ; read sectors
  1601.     bra.s    sasrw6
  1602. sasrw5:    bsr    _hwrite            ; write sectors
  1603. sasrw6:    adda    #12,sp            ; (cleanup stack)
  1604.     tst.l    d0            ; errors?
  1605.     beq    sasrwr            ; no -- success
  1606.  
  1607.     bsr    errcode            ; find error code
  1608.     cmpi.b    #MDMCHGD,d0        ; media change detected?
  1609.     beq.s    sasrw7
  1610.     cmpi.b    #WRTPRTD,d0        ; write on write-protected media?
  1611.     beq.s    sasrw9
  1612.     cmpi.b    #DRVNRDY,d0        ; drive not ready?
  1613.     beq.s    sasrwe
  1614.  
  1615.     subq.w    #1,retrycnt        ; drop retry count and retry
  1616.     bpl    sasrw1
  1617.  
  1618.     move    6(sp),d1        ; get r/w and flags word
  1619.     move.l    #EREADF,d0        ; read error code
  1620.     btst    #0,d1            ; is it a write?
  1621.     beq.s    sasrwa
  1622.     move.l    #EWRITF,d0        ; write error code
  1623.     bra.s    sasrwa
  1624.  
  1625. sasrw7:    move.w    6(sp),d1        ; get r/w and flags word
  1626.     andi.b    #$a,d1            ; no media change/physical operation?
  1627.     beq.s    sasrw8            ; if not, return media change
  1628.     move.b    #1,d0            ; d0.b = medium may have changed
  1629.     move.w    $12(a6),d1        ; d1.w = dev number
  1630.     move.b    cpun+1,d2        ; d2.b = physical unit number
  1631.     bsr    s_mc_xst        ; set mcflgs and xst flags for dev
  1632.     bra    sasrw0            ; start all over
  1633.     
  1634. sasrw8:    move.l    #E_CHNG,d0        ; media change detected
  1635.     bra.s    sasrwr            ; return
  1636.  
  1637. sasrw9:    move.l    #EWRPRO,d0        ; write on write-protected media
  1638.     bra.s    sasrwf
  1639.  
  1640. sasrwe:    move.l    #EDRVNR,d0        ; drive not ready
  1641. sasrwf:    move.w    6(sp),d1        ; get r/w and flags word
  1642.  
  1643. sasrwa:    btst    #3,d1            ; is this a physical operation?
  1644.     beq.s    sasrwc            ; no, call critical error handler
  1645.                     ; else find 1st drive of current unit
  1646.     lea    pun,a0            ; a0 = ptr to pun table
  1647.     move.w    cpun,d2            ; d1 = current pun
  1648.     moveq    #0,d1            ; d2 = index into pun table
  1649. sasrwb:    cmp.b    (a0,d1.w),d2        ; 1st drive of unit?
  1650.     beq.s    sasrwd            ; if so, get drive number 
  1651.     addq.w    #1,d1            ; else, get next drive number
  1652.     cmpi.w    #MAXUNITS,d1        ; reach end of pun table?
  1653.     bge.s    sasrwr            ; if so, forget it
  1654.     bra.s    sasrwb            ; else try this next drive
  1655.  
  1656. sasrwc:    move.w    $12(sp),d1        ; d1 = drive number
  1657. sasrwd:    bsr    critic
  1658.     cmpi.l    #CRITRETRY,d0        ; is it the magic RETRY code?
  1659.     beq    sasrw0            ; if yes, go retry
  1660.  
  1661. sasrwr:    move.w    (sp)+,d3        ; remember to restore d3
  1662.     rts
  1663.  
  1664.  
  1665. ;
  1666. ;----------------
  1667. ;
  1668. ; Check for media change on hard disk
  1669. ; Synopsis:    _sasi_mediach(dev)
  1670. ;        WORD dev;        4(sp).w
  1671. ;
  1672. ; Returns:    0L - media definitely has not changed
  1673. ;        1L - media _may_ have changed
  1674. ;        2L - media definitely has changed
  1675. ;
  1676. ; Uses:        d0, d1, a0, a1
  1677. ;
  1678. ; Comments:
  1679. ; Apr-4-1989    ml.    Add in grace period between _sasi_mediach()s.
  1680. ;            If _sasi_mediach() was called less than 1 s
  1681. ;            (200 _hz_200 clock ticks) ago, and medium was 
  1682. ;            not changed then, assume medium still has not 
  1683. ;            changed.
  1684. ;
  1685. _sasi_mediach:
  1686.     subq.w    #2,4(sp)        ; dev # excluding drv A and B
  1687.     move.w    4(sp),d1        ; d1 = current drive
  1688.     lea    mcflgs,a0        ; a0 = pointer to mcflgs
  1689.     moveq    #0,d0            ; d0 = mcflg for current drive
  1690.     move.b    (a0,d1.w),d0    
  1691.     tst.b    d0            ; has medium changed?
  1692.     bne.s    decided            ; if yes or maybe, return result
  1693.                     ; else verify that it has not
  1694.     move.l    lastmdctm,d2        ; time media change was last called
  1695.     cmp.l    _hz_200,d2        ; while (_hz_200 <= lastmdctm)
  1696.     bcc.s    decided            ;    assume medium not changed
  1697.  
  1698.     lea    pun,a1            ; ptr to beginning of pun table
  1699.     clr.w    d2            ; coerce byte to word
  1700.     move.b    (a1,d1.w),d2        ; d2 = pun current drive belongs to
  1701.  
  1702.     btst.b    d2,rmbits        ; is pun removable?
  1703.     beq.s    notchngd        ; if not, medium has not changed
  1704.  
  1705.     movem.w    d1-d2,-(sp)        ; else save registers
  1706.     move.w    d2,-(sp)        ; physical unit number
  1707.     bsr    testunit        ; verify by doing test unit ready
  1708.     addq.l    #2,sp
  1709.     movem.w    (sp)+,d1-d2        ; restore registers
  1710.     move.l    _hz_200,lastmdctm    ; update time for last _sasi_mediach()
  1711.     addi.l    #200,lastmdctm        ; 
  1712.     tst.w    d0            ; return good status?
  1713.     beq.s    notchngd        ; if yes, return medium not changed
  1714.     moveq    #1,d0            ; else return medium may have changed
  1715.     bsr    s_mc_xst        ; set mcflgs and xst flags to 1's
  1716.     bra.s    decided
  1717. notchngd:
  1718.     moveq    #0,d0            ; return medium has not changed
  1719. decided:
  1720.     rts
  1721.  
  1722.  
  1723. ;+
  1724. ; s_mc_xst - set mcflgs and drive existence flags 
  1725. ;         for drives belonging to a physical unit 
  1726. ;         to value passed
  1727. ;
  1728. ; Passed:    d0.b - value to set to
  1729. ;         d1.w - dev number
  1730. ;        d2.b - physical unit #
  1731. ;-
  1732. s_mc_xst:
  1733.     movem.l    a0-a2,-(sp)    ; save registers
  1734.     move.w    d1,-(sp)    ; save dev number
  1735.     lea    mcflgs,a0    ; a0 = ptr to mcflgs table
  1736.     lea    pun,a1        ; a1 = ptr to pun table
  1737.     lea    xst,a2        ; a2 = ptr to drive existence table
  1738. back:    cmp.b    (a1,d1.w),d2    ; does this drive belongs to this physical unit?
  1739.     bne.s    oppdir        ; if not, try opposition direction
  1740.     move.b    d0,(a0,d1.w)    ; else change its mcflg to value passed
  1741.     move.b    d0,(a2,d1.w)    ; and change its xst to value passed
  1742.     dbra    d1,back        ; try next one in backward direction
  1743. oppdir:    move.w    (sp)+,d1    ; get device number again
  1744. forth:    addq.w    #1,d1        ; try next one in forward direction
  1745.     cmp.w    #MAXUNITS,d1    ; all units checked?
  1746.     bge.s    setr        ; if yes, get ready to return
  1747.     cmp.b    (a1,d1.w),d2    ; does this drive belongs to this physical unit?
  1748.     bne.s    setr        ; if not, get ready to return
  1749.     move.b    d0,(a0,d1.w)    ; else change its mcflg to value passed
  1750.     move.b    d0,(a2,d1.w)    ; and change its xst to value passed
  1751.     bra.s    forth        ; continue to search
  1752. setr:    movem.l    (sp)+,a0-a2    ; restore registers
  1753.     rts
  1754.  
  1755.  
  1756. ;
  1757. ;--------------------- Low-Level Driver -------------------
  1758.  
  1759. ;----------------
  1760. ;
  1761. ;  Hardware definitions
  1762. ;
  1763. wdc        equ    $ffff8604
  1764. wdl        equ    $ffff8606
  1765. wdcwdl        equ    wdc        ; used for long writes
  1766. xwdl        equ    wdl-wdc        ; offset from wdc to wdl
  1767.  
  1768. dmahi        equ    $ffff8609
  1769. dmamid        equ    dmahi+2
  1770. dmalow        equ    dmamid+2
  1771. gpip        equ    $fffffa01
  1772.  
  1773.  
  1774. ;----------------
  1775. ;
  1776. ;  Tunable (delay) values
  1777. ;
  1778. ltimeout        equ    600        ; long-timeout (3 S)
  1779. stimeout        equ    20        ; short-timeout (100 mS)
  1780.  
  1781.  
  1782. ;----------------
  1783. ;
  1784. ; LONG _qdone() - Wait for command byte handshake
  1785. ; LONG _fdone() - Wait for operation complete
  1786. ; Passed:    nothing
  1787. ;
  1788. ; Returns:    EQ: no timeout
  1789. ;        MI: timeout condition
  1790. ;
  1791. ; Uses:        D0
  1792. ;
  1793. ; each pass through the loop takes 6.75 uS
  1794. ;-
  1795. _fdone:    move.l    _hz_200,d0
  1796.     add.l    #ltimeout,d0
  1797.     bra.s    qd1
  1798.  
  1799. _qdone:    move.l    _hz_200,d0
  1800.     add.l    #stimeout,d0
  1801.  
  1802. qd1:    cmp.l    _hz_200,d0        ; timeout?
  1803.     bcs.s    qdq            ; (i give up, return NE)
  1804.     btst    #5,gpip            ; interrupt?
  1805.     bne.s    qd1            ; (not yet)
  1806.  
  1807.     moveq    #0,d0            ; return EQ (no timeout)
  1808.     rts
  1809.  
  1810. qdq:    moveq    #-1,d0
  1811.     rts
  1812.  
  1813.  
  1814. ;----------------
  1815. ;
  1816. ; Wait for end of SASI command
  1817. ;
  1818. ; Passed:    d0 value to be written to wdl
  1819. ;
  1820. ; Returns:    EQ: success (error code in D0.W)
  1821. ;        MI: timeout (-1 in D0.W)
  1822. ;        NE: failure (SASI error code in D0.W)
  1823. ;
  1824. ; Uses:        d0,d1
  1825. ;-
  1826. _endcmd: move    d0,d1            ; preserve wdl value
  1827.  
  1828.     bsr    _fdone            ; wait for operation complete
  1829.     bmi.s    endce            ; (timed-out, so complain)
  1830.  
  1831.     move.w    d1,wdl
  1832.     move.w    wdc,d0            ; get the result
  1833.     and.w    #$00ff,d0        ; (clean it up), if non-zero should
  1834.                     ; do a ReadSense command to learn more
  1835. endce:    move.l    _hz_200,lastacstm    ; update controller last accessed time
  1836.     addq.l    #2,lastacstm        ; lastacstm = _hz_200 + 2;
  1837.     rts                
  1838.  
  1839.  
  1840. ;+
  1841. ;  Handle command timeout;
  1842. ;  Unlock DMA chip and return completion status;
  1843. ;-
  1844. _hto:    moveq    #-1,d0        ; indicate timeout
  1845. _hdone:    move.w    #$80,wdl    ; Landon's code seems to presume we
  1846.     tst.w    wdc
  1847.     clr    flock        ; NOW, signal that we are done
  1848.     rts
  1849.  
  1850.  
  1851. ;+
  1852. ; delay()
  1853. ;    5 - 10ms kludge delay for message byte sent back by controller.
  1854. ;-
  1855. _delay:    move.l    lastacstm,d0        ; d0 = controller last accessed time
  1856. wait:    cmp.l    _hz_200,d0        ; while (_hz_200 <= lastacstm)
  1857.     bcc.s    wait            ;    wait()
  1858.     rts
  1859.  
  1860.  
  1861. ;
  1862. ;-----------------
  1863. ;
  1864. ; _hread(sectno, count, buf, dev)
  1865. ; LONG sectno;         4(sp)
  1866. ; WORD count;         8(sp)
  1867. ; LONG buf;        $a(sp)    $b=high, $c=mid, $d=low
  1868. ; WORD dev;        $e(sp)
  1869. ;
  1870. ; Returns:    -1 on timeout
  1871. ;        0 on success
  1872. ;        nonzero on error
  1873. ;
  1874. ;-
  1875. _hread:    bsr    _delay
  1876.     movea.l    #wdc,a0            ; pointer to DMA chip
  1877.     st    flock            ; lock FIFO
  1878.  
  1879.     move    #$88,xwdl(a0)    ;wdl
  1880.     clr.l    d0
  1881.     move.w    $0e(sp),d0        ; get unit number
  1882.     lsl.w    #5,d0
  1883.     swap    d0
  1884.     ori.l    #$0008008a,d0        ; 08 wdc, 8a wdl
  1885.     move.l    d0,(a0)     ;wdcwdl
  1886.  
  1887.     move.l    $a(sp),-(sp)        ; set DMA address
  1888.     bsr    _setdma
  1889.     addq.l    #4,sp
  1890.  
  1891.     bsr    _setss            ; set sector and size
  1892.     bmi    _hto
  1893.  
  1894.     move.w    #$190,xwdl(a0)    ;wdl
  1895.     move.w    #$90,xwdl(a0)    ;wdl
  1896.     move.w    8(sp),(a0)     ;wdc    ; write sector count to DMA chip
  1897.     move.w    #$8a,xwdl(a0)    ;wdl
  1898.     move.l    #$00000000,(a0) ;wdcwdl    ; control byte  0 wdc 0 wdl
  1899.  
  1900.     move.w    #$8a,d0
  1901.     bsr    _endcmd
  1902.  
  1903. hrx:    bra    _hdone            ; cleanup after IRQ
  1904.  
  1905.  
  1906. ;
  1907. ;----------------
  1908. ;
  1909. ; _hwrite(sectno, count, buf, dev)
  1910. ; LONG sectno;         4(sp)
  1911. ; WORD count;         8(sp)
  1912. ; LONG buf;        $a(sp)    $b=high, $c=mid, $d=low
  1913. ; WORD dev;        $e(sp)
  1914. ;
  1915. ;-
  1916. _hwrite:
  1917.     bsr    _delay
  1918.     movea.l    #wdc,a0            ; pointer to DMA chip
  1919.     st    flock            ; lock FIFO
  1920.  
  1921.     move.l    $a(sp),-(sp)        ; set DMA address
  1922.     bsr    _setdma
  1923.     addq.l    #4,sp
  1924.  
  1925.     move.w    #$88,xwdl(a0)    ;wdl
  1926.     clr.l    d0
  1927.     move.w    $0e(sp),d0        ; get unit number
  1928.     lsl.w    #5,d0
  1929.     swap    d0
  1930.     ori.l    #$000a008a,d0        ; 0a wdc 8a wdl
  1931.     move.l    d0,(a0)     ;wdcwdl
  1932.  
  1933.     bsr    _setss
  1934.     bmi    _hto
  1935.  
  1936.     move.w    #$90,xwdl(a0)    ;wdl
  1937.     move.w    #$190,xwdl(a0)    ;wdl
  1938.     move.w    8(sp),(a0)     ;wdc    ; sector count for DMA chip's benefit
  1939.     move.w    #$18a,xwdl(a0)
  1940.     move.l    #$00000100,(a0) ;wdcwdl
  1941.  
  1942.     move.w    #$18a,d0
  1943.     bsr    _endcmd
  1944.  
  1945. hwx:    bra    _hdone            ; cleanup after IRQ
  1946.  
  1947.  
  1948. ;
  1949. ;----------------
  1950. ;
  1951. ; Set DMA address
  1952. ;
  1953. ; void _setdma(addr)
  1954. ; LONG addr;
  1955. ;-
  1956. _setdma:
  1957.     move.b    7(sp),dmalow
  1958.     move.b    6(sp),dmamid
  1959.     move.b    5(sp),dmahi
  1960.     rts
  1961.  
  1962.  
  1963. ;----------------
  1964. ;
  1965. ; Set sector number and number of sectors
  1966. ;
  1967. _setss:    move.w    #$8a,xwdl(a0)
  1968.  
  1969.     bsr    _qdone            ; wait for controller to take command
  1970.     bmi    setsse
  1971.  
  1972.     move.b    9(sp),d0        ; construct sector#
  1973.     swap    d0
  1974.     move.w    #$008a,d0
  1975.     move.l    d0,(a0)     ;wdcwdl    ; write MSB sector# + devno
  1976.     bsr    _qdone
  1977.     bmi    setsse
  1978.  
  1979.     move.b    10(sp),d0        ; write MidSB sector#
  1980.     swap    d0
  1981.     move.w    #$008a,d0
  1982.     move.l    d0,(a0)     ;wdcwdl
  1983.     bsr    _qdone
  1984.     bmi    setsse
  1985.  
  1986.     move.b    11(sp),d0        ; write LSB sector#
  1987.     swap    d0
  1988.     move.w    #$008a,d0
  1989.     move.l    d0,(a0)     ;wdcwdl
  1990.     bsr    _qdone
  1991.     bmi    setsse
  1992.  
  1993.     move.w    12(sp),d0        ; write sector count
  1994.     swap    d0
  1995.     move.w    #$008a,d0
  1996.     move.l    d0,(a0)     ;wdcwdl
  1997.     bsr    _qdone
  1998.  
  1999. setsse:    rts
  2000.  
  2001.  
  2002. ;
  2003. ;----------------
  2004. ;
  2005. ;  _inquiry - get device-specific parameters
  2006. ;
  2007. ;    Synopsis:    LONG _inquiry(physunit#, parms)
  2008. ;        WORD physunit#;            4(sp).W
  2009. ;        char *parms;            6(sp).L
  2010. ;
  2011. ; Old driver uses these two lines which do NOT do 
  2012. ; "d0 = (dev << 5) << 16" because the hi word of
  2013. ; D0 before the swap (lo word after) is garbage.
  2014. ;    lsl.b    #5,d0
  2015. ;    swap    d0
  2016. ;-
  2017. _inquiry:
  2018.     bsr    _delay
  2019.     st    flock            ; lock FIFO
  2020.     move.l    6(sp),-(sp)        ; -> parameter block address
  2021.     bsr    _setdma            ; set DMA there
  2022.     addq.l    #4,sp
  2023.     movea.l    #wdc,a0            ; pointer to DMA chip
  2024. ; write command and phyunit#
  2025.     move.w    #$88,xwdl(a0)    ;wdl
  2026.     move.w    4(sp),d0        ; d0 = (physunit# << 5) << 16
  2027.     moveq    #21,d1
  2028.     lsl.l    d1,d0            
  2029.     or.l    #$0012008a,d0        ; write physunit# + Inquiry + FIFO bits
  2030.     move.l    d0,(a0)        ;wdcwdl    ; inquiry+physunit# wdc 8a wdl (byte 0)
  2031.     bsr    _qdone
  2032.     bmi    inq
  2033.  
  2034.     move.l    #$8a,d1            ; d1 = byte to be sent
  2035.     move.l    d1,(a0)        ;wdcwdl    ; byte 1
  2036.     bsr    _qdone
  2037.     bmi    inq
  2038.  
  2039.     move.l    d1,(a0)        ;wdcwdl    ; byte 2
  2040.     bsr    _qdone
  2041.     bmi    inq
  2042.  
  2043.     move.l    d1,(a0)        ;wdcwdl    ; byte 3
  2044.     bsr    _qdone
  2045.     bmi    inq
  2046.  
  2047.     move.l    #$0010008a,(a0)    ;wdcwdl    ; 16 byte of parameters (byte 4)
  2048.     bsr    _qdone
  2049.     bmi    inq
  2050.  
  2051.     move.w    #$190,xwdl(a0)    ;wdl    ; reset the DMA chip
  2052.     move.w    #$90,xwdl(a0)    ;wdl
  2053.     move.w    #$01,(a0)    ;wdc    ; 1 sector of DMA (actually less)
  2054.     move.w    #$8a,xwdl(a0)    ;wdl
  2055.     move.l    #0,(a0)        ;wdcwdl    ; byte 5 (control byte)
  2056.     move.w    #$8a,d0            ; wdl value
  2057.     bsr    _endcmd            ; wait for command completion
  2058. inq:    bra    _hdone
  2059.  
  2060.  
  2061. ;
  2062. ;---------------
  2063. ;
  2064. ;  LONG _rq_sense() - get non-extended sense data from target
  2065. ;  LONG _rq_xsense() - get extended sense data from target
  2066. ;
  2067. ;  Passed:
  2068. ;    WORD physunit#;            4(sp).W        $6(sp).w
  2069. ;    char data[];            6(sp).L        $8(sp).l
  2070. ;
  2071. ;  Returns:
  2072. ;        0 : OK
  2073. ;    non-0 : ERROR
  2074. ;
  2075. _rq_sense:
  2076.     moveq    #3,d2            ; do it 4 times
  2077.     move.w    #0,-(sp)        ; request 4 bytes of sense data
  2078.     bra.s    rq0
  2079. _rq_xsense:
  2080.     moveq    #0,d2            ; do it one time
  2081.     move.w    #16,-(sp)        ; request 16 bytes of sense data
  2082. rq0:    bsr    _delay            ; kludge delay
  2083.     movea.l    #wdc,a0
  2084.     st    flock            ; lock FIFO
  2085.     move.l    8(sp),-(sp)        ; -> sense data buffer address
  2086.     bsr    _setdma            ; set DMA there
  2087.     addq.l    #4,sp
  2088.  
  2089.      move.w    #$190,xwdl(a0)    ;wdl    ; reset the DMA chip
  2090.     move.w    #$90,xwdl(a0)    ;wdl
  2091.     move.w    #$01,(a0)    ;wdc    ; 1 sector of DMA (actually less)
  2092.  
  2093.     moveq    #0,d0
  2094. rq1:    move.w    #$88,xwdl(a0)    ;wdl
  2095.     move.w    6(sp),d0        ; d0 = (dev << 5) << 16
  2096.     lsl.b    #5,d0
  2097.     swap    d0            ; in upper word
  2098.     or.l    #$0003008a,d0        ; write dev#+Request Sense+FIFO bits
  2099.     move.l    d0,(a0)        ;wdcwdl    ; rqsense+dev wdc 8a wdl (byte 0)
  2100.     bsr    _qdone
  2101.     bmi.s    wdq1
  2102.  
  2103.     move.l    #$8a,d1        ; byte to be sent
  2104.     move.l    d1,(a0)        ;wdcwdl    ; byte 1
  2105.     bsr    _qdone
  2106.     bmi.s    wdq1
  2107.  
  2108.     move.l    d1,(a0)        ;wdcwdl    ; byte 2
  2109.     bsr    _qdone
  2110.     bmi.s    wdq1
  2111.  
  2112.     move.l    d1,(a0)        ;wdcwdl    ; byte 3
  2113.     bsr    _qdone
  2114.     bmi.s    wdq1
  2115.  
  2116.     move.w    (sp),d0            ; # bytes of sense data requested
  2117.     swap    d0
  2118.     or.l    d1,d0
  2119.     move.l    d0,(a0)        ;wdcwdl    ; byte 4
  2120.     bsr    _qdone
  2121.     bmi.s    wdq1
  2122.  
  2123.     move.w    #$8a,xwdl(a0)    ;wdl
  2124.     move.l    #0,(a0)        ;wdcwdl    ; byte 5 (control byte)
  2125.     move.w    #$8a,d0            ; wdl value
  2126.     bsr    _endcmd            ; wait for command completion
  2127.     tst.w    d0
  2128.     bmi.s    wdq1
  2129.     dbra    d2,rq1            ; go back until done
  2130. wdq1:    addq.l    #2,sp            ; clean up stack
  2131.     bra    _hdone
  2132.  
  2133.  
  2134. ;
  2135. ;----------------
  2136. ;
  2137. ;  testunit - Test Unit Ready
  2138. ;
  2139. ;    Synopsis:    LONG testunit(dev)
  2140. ;        WORD dev;        4(sp).W
  2141. ;
  2142. ;    Uses:  d0, d1, and a0
  2143. ;-
  2144. tst:    dc.b    0    ; format command + devno (upper 3 bits)
  2145.     dc.b    0    ; (unused)
  2146.     dc.b    0    ; (unused)
  2147.     dc.b    0    ; (unused)
  2148.     dc.b    0    ; (unused)
  2149.     dc.b    0    ; (unused)
  2150. .even
  2151.  
  2152. testunit:
  2153.     bsr    _delay
  2154.     move.w    4(sp),d0        ; set dev#
  2155.     lsl.b    #5,d0            ; up 5 bits, fill in 0s
  2156.     move.b    d0,tst            ; stuff into command frame
  2157.     lea    tst(pc),a0        ; pick up pointer to the command block
  2158.     clr.w    d0
  2159.     st    flock            ; lock FIFO
  2160.     move.w    #$88,wdl
  2161.     move.b    (a0)+,d0        ; get the command byte
  2162.     swap    d0
  2163.     move.w    #$8a,d0
  2164.     move.l    d0,wdc            ; byte wdc 8a wdl
  2165.  
  2166.     moveq    #(5-1),d1        ; write remaining 5 bytes of command
  2167. tst1:    bsr    _qdone
  2168.     bmi    _hto
  2169.     move.b    (a0)+,d0        ; next byte of command
  2170.     swap    d0
  2171.     move.w    #$8a,d0
  2172.     move.l    d0,wdcwdl
  2173.     dbra    d1,tst1
  2174.     bsr    _endcmd            ; wait for command completion
  2175.     bra    _hdone            ; cleanup after IRQ
  2176.  
  2177.  
  2178. ;
  2179. ;---------------- Resident Installer -------------------
  2180.  
  2181. isasi5:    move.l    #(i_sasi1-i_sasi),tokeep ; at least keep this much
  2182.  
  2183.     cmpi.w    #512,maxssz    ; maxssz > 512 bytes?
  2184.     bls.s    nboot0        ; if not, don't need to replace GEMDOS buffers
  2185.                 ; else check if there is enough memory for
  2186. chkmem:    bsr    chklstmem    ;   new GEMDOS buffer lists
  2187.     tst.l    d0        ; enough?
  2188.     bpl.s    okbig        ; if so, build the list
  2189.     move.w    minbigsect,d0    ; d0 = minimum big sector
  2190.     cmp.w    maxssz,d0    ; is maxssz >= minimum big sector?
  2191.     bcc.s    regsect        ; if so, give up
  2192.     move.w    d0,maxssz    ; else try minimum big sector
  2193.     bra.s    chkmem
  2194. regsect:
  2195.     move.w    #512,maxssz    ; else, cannot handle big sectors
  2196.     bra.s    nboot0
  2197.  
  2198. okbig:    move.l    d1,tokeep    ; update amout of memory to be kept
  2199.     lea    i_sasi1,a0    ; a0 = ptr to beginning of new buffer lists
  2200.     moveq    #3,d1        ; d1 = count = 4 buffers - 1
  2201.     bsr    list_init    ; initialize the buffer list
  2202.     clr.l    (a0,d0.w)    ; cut 1 list of 4 buffers to 2 lists of 2
  2203.     move.l    a0,_bufl    ; _bufl[0] -> 1st new buffer list
  2204.     add.l    d0,d0        ; d0 = offset to beginning of 2nd buffer list
  2205.     adda.l    d0,a0        ; a0 = head of 2nd buffer list
  2206.     move.l  a0,_bufl+4    ; _bufl[1] -> 2nd new buffer list
  2207.  
  2208. nboot0:    bsr    pool_install    ; attempt to install more OS pool
  2209.     tst.w    bootloaded    ; if bootloaded, then already in super mode
  2210.     bne.s    nboot1        ; (already there)
  2211.     move.l    d0,-(sp)    ; save size of installed pool
  2212.     move.l    savssp,-(sp)    ; become a mild mannered user process
  2213.     move.w    #$20,-(sp)    ; Super(savssp)
  2214.     trap    #1
  2215.     addq.l    #6,sp
  2216.     move.l    (sp)+,d0    ; restore size of installed pool
  2217.  
  2218. nboot1:    add.l    tokeep,d0    ; compute value for Ptermres() or Mshrink
  2219.     tst.w    bootloaded    ; exit to GEMDOS?
  2220.     beq    nboot2        ; (yes -- not boot loaded)
  2221.  
  2222. ;+
  2223. ;  Return to TOS ROMs
  2224. ;    - set default boot device to C:
  2225. ;    - Print silly message
  2226. ;    - Mshrink() memory that was alloc'd to us
  2227. ;    - set magic# in D7 for TOS ROMs
  2228. ;    - RTS back to ROMs
  2229. ;-
  2230.     add.l    #$1c,d0        ; for file header
  2231.     move.l    d0,-(sp)    ; save D0
  2232.     pea    msg_loaded(pc)    ; print announcement
  2233.     move.w    #9,-(sp)
  2234.     trap    #1
  2235.     addq.l    #6,sp
  2236.     move.l    (sp)+,d0
  2237.  
  2238.     move.b    d7,d1        ; d1.b = physical unit # boot loaded from
  2239.     lsr.b    #5,d1        ;      = xxx00000 >> 5
  2240.     lea    pun,a0        ; a0 = ptr to pun table
  2241.     move.w    #0,d2        ; d2 = boot dev
  2242. bd1:    cmp.b    (a0,d2.w),d1    ; d2 belongs to physical unit booted from?
  2243.     beq    bd2        ; if yes, set (d2) as boot device
  2244.     addq.w    #1,d2        ; else try next logical unit
  2245.     bra.s    bd1
  2246. bd2:    addq.w    #2,d2        ; offset for drive A and B
  2247.     move.w    d2,_bootdev    ; set default boot device to (d2)
  2248.  
  2249.     move.l    d0,-(sp)
  2250.     move.l    baseaddr,-(sp)
  2251.     clr.w    -(sp)
  2252.     move.w    #$4a,-(sp)    ; Mshrink(...)
  2253.     trap    #1
  2254.     adda    #12,sp        ; (cleanup stack)
  2255.  
  2256.     move.w    _bootdev,-(sp)    ; set boot dev as default drive
  2257.     move.w    #$e,-(sp)    ; Dsetdrv(_bootdev)
  2258.     trap    #1
  2259.     addq.l    #4,sp        ; cleanup stack
  2260.  
  2261.     move.l    rootpath,-(sp)    ; set root as current directory
  2262.     move.w    #$3b,-(sp)    ; Dsetpath('\')
  2263.     trap    #1
  2264.     addq.l    #6,sp        ; cleanup stack
  2265.  
  2266.     move.l    _sysbase,a0    ; get the system header address
  2267.     move.l    $18(a0),d0    ; d0.l = MMDDYYYY of ROM date
  2268.     swap    d0        ; d0.l = YYYYMMDD of ROM date
  2269.     cmp.l    #CHKDATE,d0    ; does this version of ROM need bootstop?
  2270.     bcs.s    stopall        ; yup, if OS is built before 4/22/87
  2271.     move.b    puns+1,d7    ; else processed units from booting
  2272.     subq.b    #1,d7        ; unit # = # of units - 1
  2273.     lsl.b    #5,d7
  2274.     rts            ; return to TOS ROMs
  2275.  
  2276. stopall:
  2277.     move.b    #$100-$20,d7    ; prevent any other unit from booting
  2278.     rts            ; return to TOS ROMs
  2279.  
  2280. rootpath:
  2281.     dc.b    '\\',0
  2282. msg_loaded:
  2283.     dc.b    '----------------------',13,10
  2284.     dc.b    'Atari Hard Disk Driver',13,10
  2285.     dc.b    'AHDI v3.00 Apr-11-1989',13,10
  2286.     dc.b    '----------------------',13,10
  2287.     dc.b    0
  2288. .even
  2289.  
  2290. ;
  2291. ;  Terminate and stay resident;
  2292. ;  installed driver under GEMDOS.
  2293. ;
  2294. nboot2:    add.l    #$0100,d0    ; for basepage
  2295.     move.w    #0,-(sp)    ; exit code
  2296.     move.l    d0,-(sp)
  2297.     move.w    #$31,-(sp)    ; terminate and stay resident
  2298.     trap    #1        ; should never come back...
  2299.     illegal
  2300.  
  2301.  
  2302.  
  2303. ;+
  2304. ; list_init - Initialize a GEMDOS buffer list (BCBs are contiguous)
  2305. ;
  2306. ; Passed:
  2307. ;     a0.l = head of buffer list            (not changed)
  2308. ;    d0.l = size of each BCB (including data block)    (not changed)
  2309. ;    d1.w = count
  2310. ;         = number of buffers to be installed to the list - 1
  2311. ;
  2312. ; Uses:
  2313. ;    d1, a1
  2314. ;-
  2315. list_init:
  2316.     move.l    a0,-(sp)    ; save head of buffer list
  2317. lin0:    movea.l    a0,a1        ; a1 = ptr to next BCB
  2318.     adda.l    d0,a1        ;    = ptr to curr BCB + size of BCB
  2319.     move.l    a1,(a0)        ; b_link -> next BCB
  2320.     move.w    #-1,4(a0)    ; b_neg1 = -1
  2321.     adda.w    #BCBLEN,a0    ; a0 = ptr to BCB data block
  2322.     move.l    a0,-4(a0)    ; b_bufr -> b_space
  2323.     movea.l    a1,a0
  2324.     dbra    d1,lin0
  2325.     suba.l    d0,a0        ; a0 = ptr to last BCB
  2326.     clr.l    (a0)        ; lastBCB.b_link = NULL
  2327.     move.l    (sp)+,a0    ; restore head of buffer list
  2328.     rts
  2329.  
  2330.  
  2331. ;+
  2332. ; chklstmem - check if enough memory is allocated to replace GEMDOS
  2333. ;        buffer lists
  2334. ;
  2335. ; Returns:
  2336. ;    d0.l = size of each BCB (including data block)
  2337. ;         or -1 if not enough memory is allocated
  2338. ;
  2339. ; Uses:
  2340. ;    d0, d1
  2341. ;-
  2342. chklstmem:
  2343.     moveq    #BCBLEN,d0    ; d0.l = size of each BCB (inc. data block)
  2344.     add.w    maxssz,d0    ;      = BCB header len + data block size
  2345.     move.l    d0,d1        ; d1.l = d0.l * 4 
  2346.     lsl.l    #2,d1        ;      = total size of buffer lists
  2347.     add.l    tokeep,d1    ; d1.l = size needed
  2348.     cmp.l    memalloc,d1    ; enough memory allocated?
  2349.     bls.s    chk0        ; if so return
  2350.     moveq    #-1,d0        ; else return error
  2351. chk0:    rts
  2352.  
  2353.  
  2354. ;
  2355. ;+
  2356. ; pread(sectno, cnt, buf, physunit, flag)
  2357. ; LONG sectno;
  2358. ; BYTE *buf; (word aligned)
  2359. ; WORD cnt,physunit,flag;
  2360. ;
  2361. ; Passed:    flag.w            $10(sp)    
  2362. ;        dev.w        $a(a0)    $e(sp)
  2363. ;        &buf.l        $6(a0)    $a(sp)
  2364. ;        cnt.w        $4(a0)    $8(sp)
  2365. ;        sectno.l    $0(a0)    $4(sp)
  2366. ;
  2367. ; flag = 1 -- return media change if detected
  2368. ; flag = 0 -- ignore media change
  2369. ;
  2370. ; Returns:    -1 if we could not read it
  2371. ;            (may not exist)
  2372. ;-
  2373. _pread:
  2374. pread:    move    _retries,retrycnt
  2375. pread1:    lea    4(sp),a0        ; frame pointer
  2376.     move.w    $a(a0),-(sp)        ; push physical unit number
  2377.     move.l    $6(a0),-(sp)        ; buffer address
  2378.     move.w    $4(a0),-(sp)        ; number to read
  2379.     move.l    (a0),-(sp)        ; sector number
  2380.     bsr    _hread            ; hread()
  2381.     adda    #12,sp            ; clean up stack
  2382.     tst.w    d0            ; read successful
  2383.     beq    pread8            ; if so, return
  2384.     bmi.s    pread9            ; timeout, does not exist
  2385.                     ; else, it's check condition status
  2386.     move.w    $e(sp),cpun        ; cpun = current physical unit #
  2387.     bsr    errcode            ; find error code
  2388.  
  2389.     cmpi.b    #DRVNRDY,d0        ; drive not ready?
  2390.     beq.s    preadd            ; if so, return drive not ready
  2391.  
  2392.     tst.w    $10(sp)            ; ignore media change?
  2393.     beq.s    preadc            ; if so, next try
  2394.                     ; else see if it's media change error
  2395.     cmpi.b    #MDMCHGD,d0        ; media change detected?
  2396.     beq.s    pread7            ; if so, return media change
  2397.  
  2398. preadc:    subq    #1,retrycnt        ; else try try again
  2399.     bpl    pread1
  2400.  
  2401. pread9:    moveq    #EREADF,d0        ; read error
  2402.     rts
  2403.  
  2404. pread7:    moveq    #E_CHNG,d0        ; return media change detected
  2405.     rts
  2406.  
  2407. preadd:    moveq    #EDRVNR,d0        ; drive not ready
  2408.     rts
  2409.  
  2410. pread8:    clr.l    d0            ; flag no errors
  2411.     rts
  2412.  
  2413.  
  2414. ;
  2415. ;+
  2416. ; critic - call up the critical error handler.
  2417. ;
  2418. ; Passed:
  2419. ;    d0.w = error code
  2420. ;    d1.w = drive # excluding A: and B:
  2421. ;
  2422. ; Uses:
  2423. ;    d0, d1, a0
  2424. ;
  2425. ; Returns:
  2426. ;    d0.l = whatever returned by the critical handler
  2427. ;        (magic RETRY code or something)
  2428. ;-
  2429. critic:    addq.w    #2,d1            ; drive # including A: and B:
  2430.     move.w    d1,-(sp)        ; drive #
  2431.     move.w    d0,-(sp)        ; error code
  2432.     movea.l    etv_critic,a0        ; a0 = address of error handler
  2433.     jsr    (a0)            ; critic_handler(error, drive)
  2434.     addq.l    #4,sp            ; clean up stack
  2435.     rts                ; return
  2436.  
  2437.  
  2438. ;+
  2439. ; errcode - find error code for previous Check Condition Status
  2440. ;
  2441. ; Assumed:
  2442. ;    cpun = current physical unit number
  2443. ;
  2444. ; Returns:
  2445. ;    d0.b = error code    (aka additional sense code)
  2446. ;-
  2447. errcode:
  2448.     move.w    cpun,d0            ; d0 = physical unit number
  2449.     move.l    #sendata,-(sp)        ; sense data buffer
  2450.     move.w    d0,-(sp)        ; physical unit number
  2451.     btst.b    d0,scsi            ; embedded SCSI unit?
  2452.     beq.s    err0            ; if not, request non-extended sense
  2453.     bsr    _rq_xsense        ; else request extended sense
  2454.     tst.w    d0            ; successful?
  2455.     bne.s    err1            ; if not, return
  2456.     movea.l    2(sp),a0        ; a0 -> sense data buffer
  2457.     move.b    12(a0),d0        ; else d0.b = error code
  2458.     bra.s    err2            ; and return
  2459. err0:    bsr    _rq_sense        ; find out error code
  2460.     tst.w    d0            ; successful?
  2461.     bne.s    err1            ; if not, return
  2462.     movea.l    2(sp),a0        ; a0 -> sense data buffer
  2463.     move.b    (a0),d0            ; else d0.b = error code
  2464.     andi.b    #$7f,d0            ; mask valid bit
  2465.     bra.s    err2            ; and return
  2466. err1:    moveq    #-1,d0            ; error occurred
  2467. err2:    addq.l    #6,sp            ; cleanup stack
  2468.     rts
  2469.  
  2470.  
  2471. ;
  2472. ;----------------- OS Pool Expansion ------------------
  2473.  
  2474. .if ospool
  2475. ;---------------
  2476. ;
  2477. ;  Wire more pool into various ROM releases.
  2478. ;
  2479. ;    Passed:    nothing
  2480. ;    Returns:    D0 = #bytes extra used
  2481. ;
  2482. ;-
  2483. pool_install:
  2484.     move.l    _sysbase,a3        ; a3 -> base of OS
  2485.  
  2486. ; make sure we're in ROM,
  2487. ; then get address of RAM location to patch:
  2488.  
  2489.     cmp.l    #$800000,a3        ; better be ROM
  2490.     blt    notrom
  2491.     lea    pool_tab(pc),a0        ; a0 -> table to match
  2492. pi_lp:    move.l    (a0)+,d1        ; d1 = date to match
  2493.     beq    badrom            ; (forget it, end of list)
  2494.     move.l    (a0)+,a2        ; a2 -> _root address for that date
  2495.     cmp.l    $18(a3),d1        ; match dates?
  2496.     bne.s    pi_lp            ; (no -- try again)
  2497.  
  2498.     move.w    numchunks,d0        ; d0 = amount of BSS to be used
  2499.     mulu    #chunksiz,d0        ;    = # chunks * size of a chunk
  2500.     move.l    d0,d1            ; d1 = total memory needed
  2501.     add.l    tokeep,d1        ;    = already keeping + extra OS pool
  2502.     cmp.l    memalloc,d1        ; enough is allocated?
  2503.     bgt.s    bdrom2            ; if not, don't add any
  2504.                     ; else install more OS pool
  2505.     movea.l    #i_sasi+2,a0        ; a0 -> base of first buffer
  2506.     adda.l    tokeep,a0        ;    = start of file + already keeping
  2507.     move.l    a0,-(sp)        ; save base of first buffer
  2508.     move.w    numchunks,d1        ; d0 = count-1
  2509.     subq.w    #1,d1
  2510. pin_1:    lea    chunksiz(a0),a1        ; a1 -> next buffer
  2511.     move.l    a1,(a0)            ; buffer -> next one
  2512.     move.w    #chunkno,-2(a0)        ; install chunksiz
  2513.     move.l    a1,a0            ; a0 -> next buffer
  2514.     dbra    d1,pin_1        ; (do some more)
  2515.  
  2516.     sub.w    #chunksiz,a0        ; a0 -> last block
  2517.     move.l    chunkno*4(a2),(a0)    ; last block -> first in root
  2518.     move.l    (sp)+,chunkno*4(a2)     ; root -> first of ours
  2519.     rts                ; return OK
  2520.  
  2521. ;+
  2522. ;  Print warning messages
  2523. ;  about bogus versions of the
  2524. ;  operating system.  Assume that
  2525. ;  every OS past 1-May-1986 has the
  2526. ;  pool fix installed.
  2527. ;
  2528. ;-
  2529. ok_date    =    %0000110010100001    ; 1-May-1986
  2530. notrom:    lea    m_notrom(pc),a0        ; ram-based system (5/29!)
  2531.     bra.s    bdrom1
  2532. badrom:    lea    m_badrom(pc),a0        ; illegal ROM system
  2533. bdrom1:    cmp.w    #ok_date,$1e(a3)    ; if ok_date <= os_dosdate(a3) 
  2534.     bcc    bdrom2            ; then don't print anything
  2535.  
  2536.     move.l    a0,-(sp)        ; print nasty message
  2537.     move.w    #9,-(sp)
  2538.     trap    #1
  2539.     addq.l    #6,sp
  2540.  
  2541. ; print msg and wait for RETURN
  2542.     pea    keymsg(pc)
  2543.     move.w    #9,-(sp)
  2544.     trap    #1
  2545.     addq.l    #6,sp
  2546.  
  2547. bdrom3:    move.w    #2,-(sp)        ; wait for [RETURN]
  2548.     move.w    #2,-(sp)
  2549.     trap    #13
  2550.     addq.l    #4,sp
  2551.     cmp.w    #13,d0
  2552.     bne    bdrom3
  2553.  
  2554. bdrom2:    moveq    #0,d0            ; 0 extra bytes used
  2555.     rts
  2556.  
  2557. keymsg:    dc.b    'Hard disk driver not loaded; hit RETURN',13,10
  2558.     dc.b    'key to continue:',13,10
  2559.     dc.b    0
  2560.  
  2561. m_notrom:
  2562.     dc.b    '*** WARNING ***',13,10,7
  2563.     dc.b    'This hard disk driver may not work with',13,10,7
  2564.     dc.b    'a disk-based version of TOS; files on',13,10,7
  2565.     dc.b    'your hard disk may be damaged.',13,10,7
  2566.     dc.b    13,10,7
  2567.     dc.b    0
  2568.  
  2569. m_badrom:
  2570.     dc.b    '*** WARNING ***',13,10,7
  2571.     dc.b    'You are using an unofficial ROM release',13,10,7
  2572.     dc.b    'of the operating system.  This driver',13,10,7
  2573.     dc.b    'may not work correctly with it.  Files',13,10,7
  2574.     dc.b    'on your hard disk may be damaged.',13,10,7
  2575.     dc.b    13,10,7
  2576.     dc.b    0
  2577.     even
  2578.  
  2579.  
  2580. ;+
  2581. ;  Table of ROM release dates / _root addresses
  2582. ;  update these for new ROM releases that need the patch.
  2583. ;
  2584. ;-
  2585. pool_tab:
  2586.     dc.l    $11201985,$56fa        ; USA and UK, 20-Nov-1985
  2587.     dc.l    $02061986,$56fa        ; Germany, 6-Feb-1986
  2588.     dc.l    $04241986,$56fa        ; France, 24-Apr-1986
  2589.     dc.l    0            ; end of list
  2590.  
  2591. .endif
  2592.  
  2593.  
  2594. ;
  2595. ;------------------ Driver Installation -----------------
  2596.  
  2597. ;----------------
  2598. ;
  2599. ;  Driver Installation
  2600. ;
  2601. i_sasi1:
  2602.     move.l    d0,memalloc        ; record amount of memory available
  2603.     tst.w    bootloaded        ; if boot-loaded, don't Super()
  2604.     bne    nboot3
  2605.     clr.l    -(sp)            ; it's a bird...
  2606.     move.w    #$20,-(sp)        ;    ... it's a plane ...
  2607.     trap    #1            ;      ... no, its:
  2608.     addq.l    #6,sp            ; SOOUPERUSER!
  2609.     move.l    d0,savssp        ; "Faster than a prefetched opcode..."
  2610.  
  2611. nboot3:    move    #MAXUNITS-1,d1
  2612.     moveq    #-1,d0            ; a bad pun
  2613.     lea    pun,a0
  2614. i_sasi2:
  2615.     move.b    d0,(a0)+        ; initialize all puns to be bad
  2616.     dbra    d1,i_sasi2
  2617.  
  2618.     move    #0,clun            ; cur log unit# excluding drive A & B
  2619.     move.l    #4,cdbit        ; current drive bit
  2620.     move    #0,cpun            ; current physical unit number
  2621.     move    #0,puns            ; no physical units found
  2622.     move    minbigsect,maxssz    ; initialize maximum sector size
  2623.  
  2624.     move.l    _dskbufp,pbuf        ; pbuf = buffer address of
  2625.     add.l    #512,pbuf        ;     root sector image
  2626. i_sasi3:
  2627.     clr.w    -(sp)            ; ignore media change
  2628.     move.w    cpun,-(sp)        ; physical unit number
  2629.     move.l    pbuf,-(sp)        ; buffer
  2630.     move.w    #1,-(sp)        ; 1 sector
  2631.     move.l    #0,-(sp)        ; sectno = 0; root sector
  2632.     bsr    pread            ; pread()
  2633.     adda    #14,sp
  2634.     move.w    d0,preadret        ; save pread return code
  2635.  
  2636.     move.l    #sendata,-(sp)        ; buffer for data inquired
  2637.     move.w    cpun,-(sp)        ; current physical unit
  2638.     bsr    _inquiry        ; inquiry(physunit, buf)
  2639.     addq.l    #6,sp            ; clean up stack
  2640.     tst.w    d0            ; Inquiry successful?
  2641.     bne.s    chkret            ; if not, unit isn't a SCSI device
  2642.                     ; else unit is a SCSI device
  2643.     movea.l    #sendata,a0        ; a0 = address of sense data
  2644.     tst.b    (a0)            ; is unit a hard drive?
  2645.     bne.s    i_sasi4            ; if not, end of chain
  2646.     move.w    cpun,d1            ; else d1 = physical unit #
  2647.     bset.b    d1,scsi            ; mark unit as embedded scsi
  2648.     btst.b    #7,1(a0)        ; removable drive?
  2649.     beq.s    chkret            ; if not removable, was read ok?
  2650.     bset.b    d1,rmbits        ; else mark unit as removable
  2651.     bra.s    found1
  2652. chkret:    tst.w    preadret        ; was pread successful?
  2653.     bne.s    i_sasi4            ; if not, not an ACSI unit, return
  2654. found1:    addq    #1,puns            ; else found a physical unit
  2655.     bsr    ppu            ; find out how it is partitioned
  2656.     tst.w    d0            ; ppu successful?
  2657.     beq.s    nxtpun            ; go on normally
  2658.                     ; else find out what's wrong
  2659.     cmpi.w    #E_CHNG,d0        ; media changed?
  2660.     beq    i_sasi3            ; if so, retry this unit
  2661.                     ; else try next physical unit
  2662. nxtpun:    addq.w    #1,cpun            ; next physical unit
  2663.     cmpi.w    #MAXACSI,cpun        ; last one yet?
  2664.     bne    i_sasi3            ; if not, continue
  2665.  
  2666. i_sasi4:
  2667.     clr.l    a5            ; zeropage ptr
  2668.     move.l    hdv_bpb(a5),o_bpb
  2669.     move.l    hdv_rw(a5),o_rw
  2670.     move.l    hdv_mediach(a5),o_mediach
  2671.  
  2672.     move.l    #hbpb,hdv_bpb(a5)    ; install our new ones
  2673.     move.l    #hrw,hdv_rw(a5)
  2674.     move.l    #hmediach,hdv_mediach(a5)
  2675.     move.l    #_puns,pun_ptr(a5)
  2676.  
  2677.     move.l    #_cookie,cookptr    ; initialize cookie pointer
  2678.     bra    isasi5            ; must get back into resident part
  2679.  
  2680.  
  2681. ;
  2682. ;-----------------
  2683. ;
  2684. ; Partition physical unit
  2685. ;
  2686. ;
  2687. ppu:    move.w    #0,npart        ; no partition found for cpun yet
  2688.     move.w    cpun,d1            ; is cpun removable?
  2689.     btst.b  d1,rmbits        ;
  2690.     beq.s    ppu0            ; if not, go on normally
  2691.                     ; else, it's a syquest unit
  2692.     tst.w    preadret        ; is there a cartridge in there?
  2693.     bne.s    squnit            ; if not, go reserve #drv letters
  2694.                     ; else find the partitions
  2695. ppu0:    moveq    #MAXNPART,d1        ; d1 = # partition entries to check
  2696.     movea.l    pbuf,a0            ; a0 = ptr to root sector image
  2697.     cmpi.w    #SIG,DOSSIG(a0)        ; is root sector in DOS format?
  2698.     bne.s    ppu1            ; if not, assume it's in ST format
  2699.     bsr    dosppu            ; else, handle it the DOS way
  2700.     bra.s    ppu2
  2701. ppu1:    bsr    gemppu
  2702. ppu2:    tst.w    d0            ; successful?
  2703.     bne.s    ppud            ; if not, return
  2704.  
  2705.     lea    minsqnpart,a0        ; a0 = addr of least # of drives
  2706.     move.w    cpun,d1            ; d1 = unit #
  2707.     move.b    (a0,d1.w),d1        ; d0 = least # of drives requested
  2708.     sub.w    npart,d1        ; enough drives being set up?
  2709.     bls.s    ppud            ; if so, done
  2710.                     ; else see if it's removable
  2711.     move.w    cpun,d0            ; d0 = unit #
  2712.     btst.b    d0,rmbits        ; is cpun removable?
  2713.     beq.s    ppud            ; if not, done
  2714.     bra.s    sq0            ; else, set up the rest
  2715.  
  2716. squnit:    lea    minsqnpart,a0        ; a0 = addr of least # of drives
  2717.     move.w    cpun,d1            ; d1 = unit #
  2718.     move.b    (a0,d1.w),d1        ; d0 = least # of drives requested
  2719. sq0:    subq.w    #1,d1
  2720. ppu3:    move.w    d1,-(sp)        ; save count
  2721.     bsr    nxtd0
  2722.     move.w    (sp)+,d1        ; restore count
  2723.     tst.w    d0            ; a valid unit?
  2724.     bmi.s    ppud            ; if not, return
  2725.     dbra    d1,ppu3
  2726. ppud:    rts
  2727.  
  2728.  
  2729. ;
  2730. ;+
  2731. ; dosppu - find the DOS partitions of the drive and set up
  2732. ;       appropiate data structures.
  2733. ; Passed:
  2734. ;    a0 = buffer address for root sector
  2735. ;    d1 = number of entries in partition map
  2736. ;
  2737. ; Returns:
  2738. ;    d0 = 0            if no error
  2739. ;       = negative #        if error found
  2740. ;-
  2741. dosppu:    adda.w    #DOSPM,a0        ; a0 = ptr to partition map
  2742. dppu0:    movem.l    d1/a0,-(sp)        ; save count and offset
  2743.     sf    ext            ; not dealing with ext partition
  2744.     bsr    fdpart            ; find partitions
  2745.     tst.b    d0            ; found any?
  2746.     beq.s    dppua            ; not a valid partition
  2747.     cmpi.b    #5,d0            ; extended partition?
  2748.     bne.s    dppu1            ; if not, it's a regular partition
  2749.     st    ext            ; else, it's an extended partition
  2750.     move.l    #0,extvol        ; offset from start of partition = 0
  2751.     move.l    d1,extrt        ; starting sector # of ext partition
  2752. dppux:    bsr    fdnxt            ; find next logical drive
  2753.     tst.b    d0            ; found any?
  2754.     beq.s    dppua            ; no logical drive found
  2755.     bmi.s    dppu2            ; error returned
  2756.     cmpi.b    #5,d0            ; extended volume?
  2757.     beq.s    dppux            ; if so, go find next logical drive
  2758. dppu1:    movem.l    d1-d2/a0,-(sp)        ; save registers
  2759.     bsr    nxtdrv            ; general set up for clun
  2760.     movem.l    (sp)+,d1-d2/a0        ; restore registers
  2761.     tst.w    d0            ; set up successful?
  2762.     beq.s    dppu3            ; if successful, continue
  2763. dppu2:    addq.l    #8,sp            ; else clean up stack
  2764.     bra.s    dppur            ; and return
  2765. dppu3:    tst.b    ext            ; clun is in ext partition?
  2766.     bne.s    dppux            ; if so, go find next ext vol
  2767. dppua:    movem.l    (sp)+,d1/a0        ; restore count and offset
  2768.     adda    #16,a0            ; index to next entry in pmap
  2769.     dbra    d1,dppu0
  2770.     moveq    #0,d0            ; get here with no error!
  2771. dppur:    rts
  2772.  
  2773.  
  2774. ;
  2775. ;+
  2776. ; gemppu - find the GEMDOS partitions of the drive and set up
  2777. ;       appropiate data structures.
  2778. ; Passed:
  2779. ;    a0 = buffer address for root sector
  2780. ;    d1 = number of entries in partition map
  2781. ;
  2782. ; Returns:
  2783. ;    d0 = 0            if no error
  2784. ;       = negative #        if error found
  2785. ;-
  2786. gemppu:    adda.w    #HDSIZ,a0        ; a0 = ptr to hard disk size
  2787.     tst.l    (a0)+            ; size? (a0 = ptr to start of pmap)
  2788.     beq.s    gppu4            ; if =0, no drive will exist
  2789. gppu0:    movem.l    d1/a0,-(sp)        ; save count and offset
  2790.     sf    ext            ; not dealing with ext partition
  2791.     bsr    fgpart            ; find partitions
  2792.     tst.b    d0            ; found any?
  2793.     beq.s    gppua            ; not a valid partition
  2794.     cmpi.b    #'X',d0            ; extended partition?
  2795.     bne.s    gppu1            ; if not, it's a regular partition
  2796.     st    ext            ; else, it's an extended partition
  2797.     move.l    #0,extvol        ; offset from start of partition = 0
  2798.     move.l    d1,extrt        ; starting sector # of ext partition
  2799. gppux:    bsr    fgnxt            ; find next logical drive
  2800.     tst.b    d0            ; found any?
  2801.     beq.s    gppua            ; no logical drive found
  2802.     bmi.s    gppu2            ; error returned
  2803.     cmpi.b    #'X',d0            ; extended volume?
  2804.     beq.s    gppux            ; if so, go find next logical drive
  2805. gppu1:    movem.l    d1-d2/a0,-(sp)        ; save registers
  2806.     bsr    nxtdrv            ; general set up for clun
  2807.     movem.l    (sp)+,d1-d2/a0        ; restore registers
  2808.     tst.w    d0            ; set up successful?
  2809.     beq.s    gppu3            ; if so, continue
  2810. gppu2:    addq.l    #8,sp            ; else clean up stack
  2811.     bra.s    gppur            ; and return
  2812. gppu3:    tst.b    ext            ; clun is in ext partition?
  2813.     bne.s    gppux            ; if so, go find next ext vol
  2814. gppua:    movem.l    (sp)+,d1/a0        ; restore count and offset
  2815.     adda    #12,a0            ; index to next entry in pmap
  2816.     dbra    d1,gppu0
  2817. gppu4:    moveq    #0,d0            ; get here with no error!
  2818. gppur:    rts
  2819.  
  2820.  
  2821. ;
  2822. ;+
  2823. ; nxtdrv    (of clun, cdbit)
  2824. ;
  2825. ; Passed:
  2826. ;    d1.l = starting sector # of clun
  2827. ; Returns:
  2828. ;    d0 = 0            if successful
  2829. ;       = negative #        if error occurred
  2830. ;-
  2831. nxtdrv:    cmpi    #MAXUNITS,clun        ; have we already hit maximum?
  2832.     bge    nxtd9            ; yes, so signal error
  2833.  
  2834.     move.w    #1,-(sp)        ; return media change if detected
  2835.     move.w    cpun,-(sp)        ; physical unit number
  2836.     move.l    #sbuf,-(sp)        ; buffer address
  2837.     move.w    #1,-(sp)        ; 1 sector
  2838.     move.l    d1,-(sp)        ; logical sector 0 of clun
  2839.     bsr    pread            ; pread(sectno, cnt, buf, phys#, flag)
  2840.     adda    #14,sp            ; clean up stack
  2841.     tst.w    d0            ; pread successful?
  2842.     bne    nxtr            ; if not, return with error code
  2843.  
  2844.     move.l    #sbuf,a0        ; a0 = addr of boot sector image
  2845.     moveq    #$b,d0            ; d0 = offset for bytes per sector
  2846.     bsr    getlhw
  2847.     tst.w    d0            ; bytes per sector = 0?
  2848.     beq.s    nxtd1            ; if so, assume ratio to be 1
  2849.  
  2850.     cmp.w    maxssz,d0        ; max sect size >= curr sect size?
  2851.     bls.s    nxtd00            ; if so, continue
  2852.     move.w    d0,maxssz        ; else max sect size = curr sect size
  2853. nxtd00:    divu    #512,d0            ; d0 = sector size ratio
  2854.     move.w    d0,sizr            ; sizr = sector size ratio
  2855.     bra.s    nxtd2            ; go on
  2856.  
  2857. nxtd0:    cmpi    #MAXUNITS,clun        ; have we already hit maximum?
  2858.     bge    nxtd9            ; yes, so signal error
  2859.  
  2860. nxtd1:    move.w    #1,sizr            ; sector size ratio assumes to be 1
  2861.  
  2862. nxtd2:    move.l    cdbit,d1        ; get the bit to turn on
  2863.     move.l    _drvbits,d0        ; tell TOS we have the drive
  2864.     or.l    d1,d0
  2865.     move.l    d0,_drvbits
  2866.  
  2867.     asl.l    #1,d1            ; put in the next bit to turn on
  2868.     move.l    d1,cdbit
  2869.  
  2870.     move    clun,d0            ; d0 = dev number
  2871.     lea    pun,a0            ; a0 = ptr to pun table
  2872.     move.b    cpun+1,(a0,d0.w)    ; clun belongs to cpun
  2873.  
  2874.     lea    sratio,a0        ; a0 = ptr to sector size ratio table
  2875.     move.b    sizr+1,(a0,d0.w)    ; save sector ratio of clun
  2876.  
  2877.     lea    xst,a0            ; a0 = ptr to drive existence table
  2878.     move.b    #1,(a0,d0.w)        ; clun may exist
  2879.  
  2880.     lea    mcflgs,a0        ; a0 = ptr to mcflgs table
  2881.     move.b    #2,(a0,d0.w)        ; clun is definitely changed
  2882.  
  2883.     addq    #1,clun            ; clun = next possible lun
  2884.     addq    #1,npart        ; one more partition found
  2885.     moveq    #0,d0            ; gets here with no error
  2886.     bra.s    nxtr
  2887.  
  2888. nxtd9:    moveq    #-1,d0            ; error!
  2889. nxtr:    rts
  2890.  
  2891.  
  2892. ;
  2893. .if    format
  2894. ;----------------
  2895. ;
  2896. ;  Parameter Block
  2897. ;
  2898. acfmt:    dc.b    4    ; format command + devno (upper 3 bits)
  2899.     dc.b    0    ; (unused)
  2900.     dc.b    0    ; (unused) data pattern
  2901. ac_in:    dc.b    0,0    ; interleave factor MSB, LSB
  2902.     dc.b    0    ; reserved
  2903. .even
  2904.  
  2905. ;---------------
  2906. ;
  2907. ;  _doformat - format hard disk
  2908. ;
  2909. ;    Synopsis:    LONG _doformat(dev, interlv)
  2910. ;        WORD dev;            4(sp).W
  2911. ;        WORD interlv;            6(sp).W
  2912. ;
  2913. _doformat:
  2914.     move.w    4(sp),d0        ; set dev#
  2915.     lsl.b    #5,d0            ; up 5 bits, fill in 0s
  2916.     or.b    #4,d0            ; OR-in with FORMAT command
  2917.     move.b    d0,acfmt        ; stuff into command frame
  2918.     move.b    6(sp),ac_in        ; set interleave
  2919.     move.b    7(sp),ac_in+1
  2920.  
  2921.     lea    acfmt(pc),a0        ; pick up pointer to the command block
  2922.     clr.w    d0
  2923.     st    flock            ; lock FIFO
  2924.     move.w    #$88,wdl
  2925.     move.b    (a0)+,d0        ; get the command byte
  2926.     swap    d0
  2927.     move.w    #$8a,d0
  2928.     move.l    d0,wdc            ; byte wdc 8a wdl
  2929.  
  2930.     moveq    #(5-1),d1        ; write remaining 5 bytes of command
  2931. fmt1:    bsr    _qdone
  2932.     bmi    _hto
  2933.     move.b    (a0)+,d0        ; next byte of command
  2934.     swap    d0
  2935.     move.w    #$8a,d0
  2936.     move.l    d0,wdcwdl
  2937.     dbra    d1,fmt1
  2938.     bsr    _endcmd            ; wait for command completion
  2939.     bra    _hdone            ; cleanup after IRQ
  2940.  
  2941.  
  2942. ;
  2943. ;----------------
  2944. ;
  2945. ;  _mode_set - set hard disk format parameters
  2946. ;
  2947. ;    Synopsis:    LONG _mode_set(dev, len, parms)
  2948. ;        WORD dev;            4(sp).W
  2949. ;        WORD len;            6(sp).W
  2950. ;        char *parms;            8(sp).L
  2951. ;
  2952. _mode_set:
  2953.     st    flock            ; lock FIFO
  2954.     move.l    8(sp),-(sp)        ; -> parameter block address
  2955.     bsr    _setdma            ; set DMA there
  2956.     addq.l    #4,sp
  2957.  
  2958. ; write command and dev#
  2959.     move.w    #$88,wdl
  2960.     move.w    4(sp),d0        ; d0 = (dev << 5) << 16
  2961.     lsl.b    #5,d0
  2962.     swap    d0            ; in upper word
  2963.     or.l    #$0015008a,d0        ; write dev# + ModeSelect + FIFO bits
  2964.     move.l    d0,wdcwdl        ; mdsel+dev wdc 8a wdl (byte 0)
  2965.     bsr    _qdone
  2966.     bmi    wdx
  2967.  
  2968.     move.l    #$0000008a,wdcwdl    ; byte 1
  2969.     bsr    _qdone
  2970.     bmi    wdx
  2971.  
  2972.     move.l    #$0000008a,wdcwdl    ; byte 2
  2973.     bsr    _qdone
  2974.     bmi    wdx
  2975.  
  2976.     move.l    #$0000008a,wdcwdl    ; byte 3
  2977.     bsr    _qdone
  2978.     bmi    wdx
  2979.  
  2980.     move.w    6(sp),d0        ; # bytes of parameter
  2981.     swap    d0            ; in upper word
  2982.     or.l    #$0000008a,d0
  2983.     move.l    d0,wdcwdl        ; byte 4
  2984.     bsr    _qdone
  2985.     bmi    wdx
  2986.  
  2987.     move.w    #$90,wdl        ; reset the DMA chip
  2988.     move.w    #$190,wdl
  2989.     move.w    #$01,wdc        ; 1 sector of DMA (actually less)
  2990.     move.w    #$18a,wdl
  2991.     move.l    #$00000100,wdcwdl    ; byte 5 (control byte)
  2992.     move.w    #$18a,d0        ; wdl value
  2993.     bsr    _endcmd            ; wait for command completion
  2994. wdx:    bra    _hdone
  2995.  
  2996. .endif  ; format
  2997.  
  2998.   
  2999. .if    mdsense
  3000. ;----------------
  3001. ;
  3002. ;  _md_sense - get hard disk format parameters
  3003. ;
  3004. ;    Synopsis:    LONG _md_sense(dev, parms)
  3005. ;        WORD dev;            4(sp).W
  3006. ;        char *parms;            6(sp).L
  3007. ;
  3008. _md_sense:
  3009.     st    flock            ; lock FIFO
  3010.     move.l    6(sp),-(sp)        ; -> parameter block address
  3011.     bsr    _setdma            ; set DMA there
  3012.     addq.l    #4,sp
  3013.  
  3014. ; write command and dev#
  3015.     move.w    #$88,wdl
  3016.     move.w    4(sp),d0        ; d0 = (dev << 5) << 16
  3017.     lsl.b    #5,d0
  3018.     swap    d0            ; in upper word
  3019.     or.l    #$001a008a,d0        ; write dev# + ModeSense + FIFO bits
  3020.     move.l    d0,wdcwdl        ; mdsense+dev wdc 8a wdl (byte 0)
  3021.     bsr    _qdone
  3022.     bmi    wdx1
  3023.  
  3024.     move.l    #$0000008a,wdcwdl    ; byte 1
  3025.     bsr    _qdone
  3026.     bmi    wdx1
  3027.  
  3028.     move.l    #$0000008a,wdcwdl    ; byte 2
  3029.     bsr    _qdone
  3030.     bmi    wdx1
  3031.  
  3032.     move.l    #$0000008a,wdcwdl    ; byte 3
  3033.     bsr    _qdone
  3034.     bmi    wdx1
  3035.  
  3036.     move.l    #$0016008a,wdcwdl    ; 22 bytes of parameters (byte 4)
  3037.     bsr    _qdone
  3038.     bmi    wdx1
  3039.  
  3040.     move.w    #$190,wdl        ; reset the DMA chip
  3041.     move.w    #$90,wdl
  3042.     move.w    #$01,wdc        ; 1 sector of DMA (actually less)
  3043.     move.w    #$8a,wdl
  3044.     move.l    #0,wdcwdl        ; byte 5 (control byte)
  3045.     move.w    #$8a,d0            ; wdl value
  3046.     bsr    _endcmd            ; wait for command completion
  3047. wdx1:    bra    _hdone
  3048.  
  3049. .endif  ; mdsense
  3050.  
  3051.     bss
  3052. clun:    ds.w    1            ; current logical unit
  3053. cdbit:    ds.l    1            ; current drive bit
  3054. sbuf:    ds.b    512            ; temporary buffer for i/o
  3055.     end
  3056.